jeshmal4u
jeshmal4u

Reputation: 41

Strict aliasing warning : typecasting uint64_t variable to a 64-bit sized structure

I am working on fixing the below problem in C-program on Linux (4.19.21-linux-gnu-gcc),

//Structure definition :

struct data_from_u64 {
uint32_t u32_value;
uint16_t u16_value;
uint8_t u8_value1;
uint8_t u8_value2;
}

//Expectation : Convert a incoming uint64_t variable to the above structure using the below macro, 

#define U64_TO_STRUCT(u64_value)  ( * (data_from_u64 *) ((void*)  &(u64_value)) )

//Usage
  data_from_u64 data = U64_TO_STRUCT(u64_value);

The project is huge that it is very widely used, but the new compilation procedure is enforcing "-O2" and "-Werror" flag while compiling. Can you help resolve the error/warning mentioned below. change should be minimal as this macro is used in more than 1000 places.

Error/Warning:

error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing] #define U64_TO_STRUCT(u64_value) ( * (data_from_u64 ) ((void) &(u64_value)) )

What have i tried :

I have tried doing memcpy, it works. But it requires to be updated in all the 1000places of usage[it requires parameter of the macro to be changed to include the destination].

Upvotes: 2

Views: 146

Answers (2)

klutt
klutt

Reputation: 31409

You can use this:

struct data_from_u64 U64_TO_STRUCT(uin64_t u64_value) {
    struct data_from_u64 ret;
    memcpy(&ret, &u64_value, sizeof u64_value);
    return ret;
}

It's a common misconception that you cannot return structs like this. You cannot return local arrays, but returning structs is perfectly fine.

And the lesson to learn from this, is that all nagging from us here at SO about "you're violating the anti aliasing rule" is not just some nerdy mumbojumbo that never matters in practice. As you can see for yourself, it does have real world consequences. :)

If you really want to have a macro for this, take a look at Eric's answer which works great, conforms to the standard and does not rely on compiler extensions. I personally just don't like function like macros.

Upvotes: 4

Eric Postpischil
Eric Postpischil

Reputation: 223795

An alternative to memcpy or the improper aliasing is to use a union with a compound literal:

#define U64_TO_STRUCT(u64_value) \
    ((union { uint64_t u; struct data_from_u64 s; }) { u64_value } .s)

Upvotes: 4

Related Questions