Why doesn't this reinterpret_cast compile?

前端 未结 11 656
暗喜
暗喜 2020-12-04 16:32

I understand that reinterpret_cast is dangerous, I\'m just doing this to test it. I have the following code:

int x = 0;
double y = reinterpret_c         


        
相关标签:
11条回答
  • 2020-12-04 16:51

    If you are trying to convert the bits of your int to a the representation of a double, you need to cast the address not the value. You must also make sure the sizes match:

    uint64_t x = 0x4045000000000000;
    double y = *reinterpret_cast<double *>(&x);
    
    0 讨论(0)
  • 2020-12-04 16:52

    reinterpret_cast is not a general cast. According to the C++03 spec section 5.2.10.1:

    Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.

    And there is nothing listed that describes converting between integral and floating point types (or between integral types, even this is illegal reinterpret_cast<long>(int(3));)

    0 讨论(0)
  • 2020-12-04 16:54

    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.

    0 讨论(0)
  • 2020-12-04 16:58

    In C++ reinterpret_cast can only perform a specific set of conversions, explicitly listed in the language specification. In short, reinterpret_cast can only perform pointer-to-pointer conversions and reference-to-reference conversions (plus pointer-to-integer and integer-to-pointer conversions). This is consistent with the intent expressed in the very name of the cast: it is intended to be used for pointer/reference reinterpretation.

    What you are trying to do is not reinterpretation. If you want to reinterpret an int as a double you'd have to convert it to a reference type

    double y = reinterpret_cast<double&>(x); 
    

    although the equivalent pointer-based reinterpretation is probably more explicit

    double y = *reinterpret_cast<double*>(&x); // same as above
    

    Note though, that while reinterpret_cast can convert the reference/pointer types, the actual attempt to read the data through the resultant reference/pointer produces undefined behavior.

    And in any case this, of course, can't make much sense on a platform with int and double of different size (since in case of larger double you will read beyond the memory occupied by x).

    So, in the end it all boils down to what you were trying to achieve. Memory reinterpretation? See above. Some kind of more meaningful int to double conversion? If so, reinterpret_cast won't help you here.

    0 讨论(0)
  • 2020-12-04 16:59

    Use a union. It is the least error-prone way to memory map between an integer and a floating point type. Reinterpreting a pointer will cause aliasing warnings.

    #include <stdio.h>
    #include <stdint.h>
    
    int main(int argc, char *argv[])
    {
        union { uint32_t i; float f; } v;  // avoid aliasing rules trouble
        v.i = 42;
        printf("int 42 is float %f\n", v.f);
        v.f = 42.0;
        printf("float 42 is int 0x%08x\n", v.i);
    }
    
    0 讨论(0)
提交回复
热议问题