Search code examples
c++castingreinterpret-caststrict-aliasingtype-punning

Does a simple cast to perform a raw copy of a variable break strict aliasing?


I've been reading about strict aliasing quite a lot lately. The C/C++ standards say that the following code is invalid (undefined behavior to be correct), since the compiler might have the value of a cached somewhere and would not recognize that it needs to update the value when I update b;

float *a;
...
int *b = reinterpret_cast<int*>(a);
*b = 1;

The standard also says that char* can alias anything, so (correct me if I'm wrong) compiler would reload all cached values whenever a write access to a char* variable is made. Thus the following code would be correct:

float *a;
...
char *b = reinterpret_cast<char*>(a);
*b = 1;

But what about the cases when pointers are not involved at all? For example, I have the following code, and GCC throws warnings about strict aliasing at me.

float a = 2.4;
int32_t b = reinterpret_cast<int&>(a);

What I want to do is just to copy raw value of a, so strict aliasing shouldn't apply. Is there a possible problem here, or just GCC is overly cautious about that?

EDIT

I know there's a solution using memcpy, but it results in code that is much less readable, so I would like not to use that solution.

EDIT2

int32_t b = *reinterpret_cast<int*>(&a); also does not work.

SOLVED

This seems to be a bug in GCC.


Solution

  • If you want to copy some memory, you could just tell the compiler to do that:

    Edit: added a function for more readable code:

    #include <iostream>
    using std::cout; using std::endl;
    #include <string.h>
    
    template <class T, class U>
    T memcpy(const U& source)
    {
        T temp;
        memcpy(&temp, &source, sizeof(temp));
        return temp;
    }
    
    int main()
    {
        float f = 4.2;
        cout << "f: " << f << endl;
    
        int i = memcpy<int>(f);
        cout << "i: " << i << endl;
    }
    

    [Code] [Updated Code]

    Edit: As user/GMan correctly pointed out in the comments, a full-featured implementation could check that T and U are PODs. However, given that the name of the function is still memcpy, it might be OK to rely on your developers treating it as having the same constraints as the original memcpy. That's up to your organization. Also, use the size of the destination, not the source. (Thanks, Oli.)