reinterpret_cast<>() v. static_cast<>()

  • Thread starter Scott Brady Drummonds
  • Start date
S

Scott Brady Drummonds

Hi, everyone,

I've checked a couple of on-line resources and am unable to determine how
reinterpret_cast<> is different from static_cast<>. They both seem to
perform a compile-time casting of one type to another. However, I'm certain
that there is something else that is happening.

Can someone explain the difference or recommend an online site that can
explain it to me?

Thanks,
Scott
 
D

David Harmon

Hi, everyone,

I've checked a couple of on-line resources and am unable to determine how
reinterpret_cast<> is different from static_cast<>. They both seem to
perform a compile-time casting of one type to another. However, I'm certain
that there is something else that is happening.

static_cast<> uses sensible, well-defined conversions. For example, the
integer 10 would be converted to the double 10.0.

reinterpret_cast<> just looks at the bits in memory in as if they were
the encoding as a different type. For example, the integer 10 would
look like some number who-knows-what as a double.
 
R

Ron Natalie

Scott Brady Drummonds said:
Hi, everyone,

I've checked a couple of on-line resources and am unable to determine how
reinterpret_cast<> is different from static_cast<>. They both seem to
perform a compile-time casting of one type to another. However, I'm certain
that there is something else that is happening.

There are two major differences:
1. static_cast won't convert certain types (you'll get a compile error).
2. when both will perform the conversion, the nature of the conversion is different.

Static_cast has two uses. First it will force a conversion that could have happened implicitly.
For example:
double value = 1.45;
double remainder = value - static_cast<int>(value);

Here we force a conversion that could be done implicitly with an extra temporary variable.
The other use, is to reverse a defined conversion. If there is a valid forward conversion,
in most cases you can reverse it with a static cast.

struct Base {
};
struct Derived : Base {
};

Derived d;
Base* bp = &d; // implicit conversion.
Derived* dp = static_cast<Derived*>(bp); // invert valid conversion.

A reinterpret cast pretty much says, treat these bits as another type. Its results are implementation
specific in most cases. You can do things like:
char* foo = ...

unsigned char* foo = reinterpret_cast<unsigned char*>(foo); // force type change!

Needless to say you should think twice in general before doing this. The compiler will
refuse to do the static_cast of the above types because they are unrelated (no conversion
defined in either direction).

Now here's a case where they both casts will do something different (in many circumstances):

struct BaseA {
char a;
};
struct BaseB {
char b;
};
struct Derived : BaseA, BaseB {
};

Derived d;
BaseB* bp = static_cast<BaseB*>(&d); // valid: bp now points to BaseB subobject of d
BaseB* rp = reinterpret_cast<BaseB*>(&d); // probably not valid, could result in rp pointing at
// the BaseA memory in d but with the BaseB* type.
 
A

AngleWyrm

Scott Brady Drummonds said:
Can someone explain the difference or recommend an online site that can
explain it to me?

static_cast<> is for related casts; (float->int, int->enum, etc).
reinterpret_cast<> is for totally unrelated type conversions (which
shouldn't usually be done). For example:

// Converting a hex number to a device port
IO_device* myDevicePort = reinterpret_cast<IO_device*>(0XFF00) // device at
0xFF00
 
F

forums_mp

Scott Brady Drummonds said:
Hi, everyone,

I've checked a couple of on-line resources and am unable to determine how
reinterpret_cast<> is different from static_cast<>. They both seem to
perform a compile-time casting of one type to another. However, I'm certain
that there is something else that is happening.

Can someone explain the difference or recommend an online site that can
explain it to me?

Thanks,
Scott

Interestingly enough I just went through the process of laying some
ground rules on the use of the C++ casts.
A synopsis of what I was able to deduce - of course the experts will
correct me if I'm mistaken

---------
reinterpret_cast is ONLY for pointers, of the same constness. You can
cast a char* to an unsigned char* or any other * with
reinterpret_cast, but you can't cast off constness with reinterpret
cast.

const_cast is to cast off constness. If you have a const char* and
ABSOLUTELY MUST get rid of its constness and KNOW FOR A FACT that that
operation is safe AND you can't just make a new copy of the buffer ...
then const_cast is your tool.

static_cast is for casting a base class to a derived class. No
runtime type checking is performed so this seems/is inherently
dangerous, but sometimes if you are stuck with a bad design ...
unavoidable. You can also cast an int to an enum using static cast,
as well as a few other things.

dynamic_cast is a "safe" way to cast a base class to a derived class,
but it requires you to include type information in your build. if at
runtime, if the cast can't be performed, then the cast returns 0,
otherwise the cast succeeds and you continue your program.

---------

Along the same lines I have a question.
Notwithstanding the C++ casts are limited in scope which in my view
implies (no proof though) that they are safer than the C variant,
whats the 'real' gain over the C cast? A question that seems to crop
up with no reasonable answer on my part. I suspect in the grand
scheme of things casting it's low level bit twiddling on both parts
(C/C++)

----------
 
C

Cy Edmunds

[snip]
Along the same lines I have a question.
Notwithstanding the C++ casts are limited in scope which in my view
implies (no proof though) that they are safer than the C variant,
whats the 'real' gain over the C cast? A question that seems to crop
up with no reasonable answer on my part. I suspect in the grand
scheme of things casting it's low level bit twiddling on both parts
(C/C++)

----------

C casts are simply too powerful (about the same as the dreaded
reinterpret_cast). For instance in some cases you can, with a single typo,
cast one pointer type to a completely different pointer type when all you
meant to do was cast away constness. If you make that mistake with a
const_cast you will get a compile time error.
 
R

Ron Natalie

forums_mp said:
static_cast is for casting a base class to a derived class. No
runtime type checking is performed so this seems/is inherently
dangerous, but sometimes if you are stuck with a bad design ...
unavoidable. You can also cast an int to an enum using static cast,
as well as a few other things.

This is incomplete. Static cast has lots of other use other than casting
from base to derived.
dynamic_cast is a "safe" way to cast a base class to a derived class,
but it requires you to include type information in your build. if at
runtime, if the cast can't be performed, then the cast returns 0,
otherwise the cast succeeds and you continue your program.

No, it requires the pointer casted from to be a polymorphic class
in most (but not all cases). If that's what you mean by "including
type information" in your build, fine, but you'd be better off using
the proper terminology.
Along the same lines I have a question.
Notwithstanding the C++ casts are limited in scope which in my view
implies (no proof though) that they are safer than the C variant,
whats the 'real' gain over the C cast? A question that seems to crop
up with no reasonable answer on my part. I suspect in the grand
scheme of things casting it's low level bit twiddling on both parts
(C/C++)

First, the fact that they are limited in scope, means that the compiler will
check inadvertent errors like changing the type when all you mean to do
is change the const etc.... Further as I pointed out in my original response,
the C++ static_, dynamic_ and reinterpret_ casts DO DIFFERENT THINGS
when presented the same casting arguments. The C-Style cast will do combinations
of static, const and reinterpret (as well as a conversion for which there is no
C++ equivalent). Yes, if you think about it, you can determine which one it
will do, but that is frequently fraught with perils.
 
J

Jerry Coffin

[ ... ]
reinterpret_cast is ONLY for pointers, of the same constness. You can
cast a char* to an unsigned char* or any other * with
reinterpret_cast, but you can't cast off constness with reinterpret
cast.

IIRC, reinterpret_cast can be used on references as well as pointers.
const_cast is to cast off constness. If you have a const char* and
ABSOLUTELY MUST get rid of its constness and KNOW FOR A FACT that that
operation is safe AND you can't just make a new copy of the buffer ...
then const_cast is your tool.

const_cast can also be used to modify volatility.
static_cast is for casting a base class to a derived class. No
runtime type checking is performed so this seems/is inherently
dangerous, but sometimes if you are stuck with a bad design ...
unavoidable. You can also cast an int to an enum using static cast,
as well as a few other things.

You should almost never use static_cast to cast between different types
in the same hierarchy -- moving up the hierarchy can be done implicitly,
and down the hierarchy should normally use dynamic_cast. static_cast
should normally be used for things like floating->integer.
dynamic_cast is a "safe" way to cast a base class to a derived class,
but it requires you to include type information in your build. if at
runtime, if the cast can't be performed, then the cast returns 0,
otherwise the cast succeeds and you continue your program.

That's how it works for pointers. For references, dynamic_cast succeeds
or throws and exception.
Along the same lines I have a question.
Notwithstanding the C++ casts are limited in scope which in my view
implies (no proof though) that they are safer than the C variant,
whats the 'real' gain over the C cast? A question that seems to crop
up with no reasonable answer on my part. I suspect in the grand
scheme of things casting it's low level bit twiddling on both parts
(C/C++)

Anything that tries to talk about "the 'real' gain" is almost certain to
be wrong. There are a number of improvements. dynamic_cast provides a
capability that a C-style cast simply doesn't provide at all.
const_cast provides a capability that a C-style cast could provide, but
is safer since it won't let you accidentally cast to some type that's
totally unrelated to the original type or something like that. From an
entirely different sort of viewpoint, it's essentially impossible to
grep for C-style casts, but trivial to do so for the new C++ casts.
 
O

Old Wolf

dynamic_cast is a "safe" way to cast a base class to a derived class,
That's how it works for pointers. For references, dynamic_cast succeeds
or throws and exception.

Is this UB:
class Base { /* ... */ };
class Derived: public Base { public: int bar; };

void foo(Base *b)
{
try {
dynamic_cast<Derived *>(b)->bar = 3;
}
catch(...) {
do_error("non-derived object passed");
}
}

I had previously assumed that this was a safe technique because
the dynamic_cast would throw. But if this is not the case, then
there is UB because of the 0-dereference (it might not even
throw an exception at all).
 
R

Ron Natalie

Old Wolf said:
I had previously assumed that this was a safe technique because
the dynamic_cast would throw. But if this is not the case, then
there is UB because of the 0-dereference (it might not even
throw an exception at all).

Correct.
 
N

Nick Hounsome

Old Wolf said:
Is this UB:
class Base { /* ... */ };
class Derived: public Base { public: int bar; };

void foo(Base *b)
{
try {
dynamic_cast<Derived *>(b)->bar = 3;
}
catch(...) {
do_error("non-derived object passed");
}
}

I had previously assumed that this was a safe technique because
the dynamic_cast would throw. But if this is not the case, then
there is UB because of the 0-dereference (it might not even
throw an exception at all).

It can never throw an exception (except in the sense that theoretically it
could
because deref. 0 is UB).

You want:

dynamic_cast<Derived&>(*b).bar = 3;

or replace the whole thing with:

if( Dervived* dp = dynamic_cast<Derived*>(b))
{
dp->bar = 3;
}
else
do_error(.....);

P.S. unless you add one or more virtual methods
to Base dynamic_cast will
not work for you anyway - it will just do the same as
static_cast which will NEVER return null (unless b is).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top