Why Doesn't This Reinterpret_Cast Compile

Why doesn't this reinterpret_cast compile?

Perhaps a better way of thinking of reinterpret_cast is the rouge operator that can "convert" pointers to apples as pointers to submarines.

By assigning y to the value returned by the cast you're not really casting the value x, you're converting it. That is, y doesn't point to x and pretend that it points to a float. Conversion constructs a new value of type float and assigns it the value from x. There are several ways to do this conversion in C++, among them:

int main()
{
int x = 42;
float f = static_cast<float>(x);
float f2 = (float)x;
float f3 = float(x);
float f4 = x;
return 0;
}

The only real difference being the last one (an implicit conversion) will generate a compiler diagnostic on higher warning levels. But they all do functionally the same thing -- and in many case actually the same thing, as in the same machine code.

Now if you really do want to pretend that x is a float, then you really do want to cast x, by doing this:

#include <iostream>
using namespace std;

int main()
{
int x = 42;
float* pf = reinterpret_cast<float*>(&x);
(*pf)++;
cout << *pf;
return 0;
}

You can see how dangerous this is. In fact, the output when I run this on my machine is 1, which is decidedly not 42+1.

reinterpret_cast Fails to Compile

I guess you are experimenting with a C++ helper library.

I happened to run into exactly the same problem about a year ago.

My workaround was to create a local temporary variable, run the factory creation with that variable as target and then copy the value into my helper class, just like this:

HRESULT HResult = DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED,
__uuidof( IDWriteFactory ),
reinterpret_cast<IUnknown**>( &pTempFactory )
);
if( HResult != 0 )System::Runtime::InteropServices::Marshal::ThrowExceptionForHR (HResult);
pBaseFactory = pTempFactory;

I am not sure if this is an elegant solution but it worked for me.

Why is reinterpret_cast not constexpr?

At runtime the C++ language has the concept of Undefined Behavior. Under certain (well specified) conditions, the program has Undefined Behavior, that means that it can exhibit any behavior: it can crash, it can hang forever, it can print gibberish, it can appear to work, or it can do anything. A simplified explanation of why this exists is performance.

At runtime this is a tradeoff (a compromise if you will), but it is unacceptable at compile time. If the standard would allow UB at compile time, not only it would be legal to get crashes while compiling the program or compile ad infinitum, but you could never be sure of the validity of the compiled executable.

As such, any form of constexpr would have to be 100% free of Undefined Behavior. No exceptions about it. No leeway.

One notorious source of UB is reinterpret_cast. There are very few valid uses of reinterpret_cast, most of them result in UB. Plus it is practically impossible to check if the use is valid. So reinterpret_cast is not allowed during compilation, i.e. it is not allowed in constexpr.

reinterpret_castunsigned long Invalid Cast

You can't reinterpret_cast between two integer types, period. That's not what reinterpret_cast is for. If you want to cast between two integer types, use static_cast.

If your goal is to really "reinterpret the bit pattern" then you'll have to cast to reference. That is, reinterpret_cast<unsigned long&>(x) is valid if x is an lvalue of type int. But now you are getting into dangerous territory, as this is in general undefined behaviour, and will probably work on a 32-bit x86 platform but will do something bad on a 64-bit x86 platform where unsigned long is longer than int.

Why Doesn't reinterpret_cast Force copy_n for Casts between Same-Sized Types?

why doesn't reinterpret_cast handle that for me?

One reason is that the size, alignment, and bit representations aren't specified, so such a conversion wouldn't be portable. However, that wouldn't really justify making the behaviour undefined, just implementation-defined.

By making it undefined, the compiler is allowed to assume that expressions of unrelated types don't access the same object, which can allow better optimisation. For example, in the following:

int   & i = something();
float & f = something_else();

const int i1 = i;
f = 42;
const int i2 = i;

the compiler can assume that i1 and i2 both have the same value (i being unchanged by the assignment to f), and optimise them into a single constant. Breaking the assumption will then cause undefined behaviour.

Or is there something else available so I don't have to jump through this hoop?

Copying the bytes is the only well-defined way to reinterpret one object type as an unrelated type.

Aliasing with reinterpret_cast or a union might work sometimes (assuming the size etc. match), but might trip you up if the optimiser gets too clever with undefined behaviour.

Why does C style cast work but reinterpret_cast doesn't?

(In layman's terms) reinterpret_cast is used to interpret the bits of an object as another type in an implementation-defined manner. You don't want that: you want a conversion (from char to int). Use static_cast instead.

(All possible uses of reinterpret_cast are listed in 5.2.10; this is not one of them.)

When to use reinterpret_cast?

The C++ standard guarantees the following:

static_casting a pointer to and from void* preserves the address. That is, in the following, a, b and c all point to the same address:

int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);

reinterpret_cast only guarantees that if you cast a pointer to a different type, and then reinterpret_cast it back to the original type, you get the original value. So in the following:

int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);

a and c contain the same value, but the value of b is unspecified. (in practice it will typically contain the same address as a and c, but that's not specified in the standard, and it may not be true on machines with more complex memory systems.)

For casting to and from void*, static_cast should be preferred.

Do constant and reinterpret cast happen at compile time?

The dynamic cast is the only that needs to be "calculated" in run-time. All other casts are calculated in compile-time.

  • The machine code for a static_cast is a fixed function based on the type you are casting FROM and TO.
  • The machine code for a const_cast is in fact nothing more than allow a const value to be passed as no-const or vice-versa. So it can be resolved in compile-time
  • For reinterpret_cast, the machine code can be resolved in compile-time as well. Once it's nothing more than "look to a pointer that is pointing to a type A with the eyes of who is looking for the type B".
  • The dynamic_cast needs to resolve virtual tables and adjust the correct addresses of virtual methods based on the type FROM and TO. That's why it's more complex!


Related Topics



Leave a reply



Submit