2

By following the rule of thumb to prefer static_cast or dynamic_cast before everything else, I wrote the following program:

int main(void)
{
    int i = 0;
    unsigned *j = static_cast<unsigned*>(&i);
    return 0;
}

However, it does not even compile:

$ g++ --std=c++11 test5.cpp 
test5.cpp: In function ‘int main()’:
test5.cpp:4:44: error: invalid static_cast from type ‘int*’ to type ‘unsigned int*’
     unsigned *j = static_cast<unsigned*>(&i);
                                            ^

Why is this wrong? What is the correct cast for this situation?

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
Vorac
  • 8,726
  • 11
  • 58
  • 101
  • 2
    You need `reinterpret_cast` for this. – kennytm May 12 '16 at 12:38
  • It wouldn't have compiled with a `dynamic_cast`, either, so the entire premise is a bit deceptive. – Kerrek SB May 12 '16 at 12:39
  • @kennytm, that's what I am trying to avoid - `reinterpret_cast` and `(unsigned*)` are evil and I try to use them only as a last resort. I wasn't expecting to need them for such a trivial task. – Vorac May 12 '16 at 12:43
  • 4
    Don't program by using emotional memory. Instead, learn the rules, analyze the problem you need to solve, and then select an appropriate implementation for the solution. If you need to reinterpret an object as a different object, you need a reinterpret-cast (but you also need to understand what is and is not allowed). – Kerrek SB May 12 '16 at 12:54

2 Answers2

8

You can static_cast from an int to an unsigned, which performs the appropriate conversion. But what you have is a pointer; this pointer points to a region of memory that is to be interpreted as an int. Dereferencing the pointer yields the int's value. static_cast will not convert between pointers to unrelated types.

int i = 0;
int* ip = &i;
int j = *ip; // treat the region pointed to as an int

To treat the memory as unsigned under dereference, you need to reinterpret the memory; that's what reinterpret_cast does.

int i = 0;
int* ip = &i;
unsigned j = *reinterpret_cast<unsigned*>(ip); // treat the region pointed to as unsigned

You shouldn't do this, however. reinterpret_cast does exactly what it says: reinterprets the memory as a different type. If the bit pattern doesn't match what would be expected for that type, the result will differ from the conversion performed by static_cast<unsigned>. This can be the case on a system where signed integers are not represented using 2's complement, for instance.

The correct approach is to dereference the int* then static_cast<unsigned> the result of that:

int i = 0;
int* ip = &i;
unsigned j = static_cast<unsigned>(*ip); // treat the region pointed to as int
                                         // then convert the int to unsigned

To summarise: static_cast will perform the integer conversion, but it won't re-interpret a memory region as a different type. That's what reinterpret_cast is for.

Andrew
  • 5,212
  • 1
  • 22
  • 40
2

You would have to use:

unsigned *j = static_cast<unsigned*>(static_cast<void*>(&i));

this is what you can read here at point 5, or simply use: reinterpret_cast:

int i = 0;
unsigned *j = reinterpret_cast<unsigned*>(&i);

often instead of using cast-s programmers use unions as below:

union {
  int n;
  unsigned char bt[4];
} data;
data.n = i;
data.bt[3] = 0xff;

As it was said in comments, using union for casting is undefined behaviour - even if it is supported by most compilers : you can read more on this here: Is using an union in place of a cast well defined? and here Is using an union in place of a cast well defined?

Community
  • 1
  • 1
marcinj
  • 48,511
  • 9
  • 79
  • 100