Reputation: 41
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: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing] #define U64_TO_STRUCT(u64_value) ( * (data_from_u64 ) ((void) &(u64_value)) )
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
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
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