According to GCC's documentation and the various answers I read on Stack Overflow, it is allowed to use unions for type punning in C, like:
union a_union { int i; double d; }; int f() { union a_union t; t.d = 3.0; return t.i; } But is it allowed to use unions to modify parts of an object? like:
#include <stdint.h> #include <assert.h> union test { uint32_t val; uint16_t part[2]; }; int main(void) { union test t; t.val = 0x12345678; t.part[0] = 0x4321; assert(t.val == 0x12344321); return 0; } Assuming our machine is little-endian, will the assert always succeed?
C standard says:
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
But I do see similar usage in many places, such as the Linux kernel.
According to this answer, since sizeof(uint16_t [2]) == sizeof(uint32_t), this does not violate the rule above.
So, I modifiy my question:
#include <stdint.h> #include <assert.h> union test { uint32_t val; uint8_t bit_0; struct { uint8_t _bit_0; uint8_t bit_8; }; }; int main(void) { union test t; t.val = 0x12345678; t.bit_0 = 0x21; t.bit_8 = 0x43; assert(t.val == 0x12344321); return 0; } Is it still valid in this situation?
unionis used for something in the language, but this is not the best use of it (probably the worst, instead) You can find that the field you try to access is not put at the proper offset due to gaps introduced by the compiler. Reinterpreting binary data stored in memory is a dangerous bend path. Unfortunately too spread to make people think it is the only way to proceed.