What are the usage scenarios and memory layout of unions in C language?
Union Basic Concepts:
-
Definition and Declaration
cunion Data { int i; float f; char str[20]; }; union Data data; data.i = 10; data.f = 3.14; strcpy(data.str, "Hello"); -
Memory Sharing Property
cunion Example { int value; char bytes[4]; }; union Example ex; ex.value = 0x12345678; // bytes[0] = 0x78 (little endian) // bytes[1] = 0x56 // bytes[2] = 0x34 // bytes[3] = 0x12
Typical Usage Scenarios:
-
Data Type Conversion
cunion FloatInt { float f; unsigned int i; }; float_to_bits(float value) { union FloatInt converter; converter.f = value; return converter.i; } -
Memory Space Saving
c// Without union: 12 bytes struct Message { int type; union { int int_data; float float_data; char char_data[4]; } data; }; // With union: only 8 bytes union CompactMessage { struct { int type; int data; } int_msg; struct { int type; float data; } float_msg; }; -
Network Protocol Parsing
cunion IPHeader { struct { unsigned int version : 4; unsigned int ihl : 4; unsigned int tos : 8; unsigned int total_length : 16; } fields; unsigned int raw; }; -
Variant Data Types
cenum DataType { INT, FLOAT, STRING }; struct Variant { enum DataType type; union { int int_val; float float_val; char *str_val; } value; };
Memory Layout Analysis:
-
Size Calculation
cunion SizeExample { char c; // 1 byte int i; // 4 bytes double d; // 8 bytes }; sizeof(union SizeExample); // 8 bytes (size of largest member) -
Alignment Rules
cunion AlignedExample { char c; int i; double d; }; // Size is 8 bytes, aligned to 8-byte boundary
Advanced Applications:
-
Bit Field Operations
cunion BitManipulation { unsigned int value; struct { unsigned int bit0 : 1; unsigned int bit1 : 1; unsigned int bit2 : 1; unsigned int rest : 29; } bits; }; union BitManipulation bm; bm.value = 0; bm.bits.bit0 = 1; -
Type-Safe Unions
cstruct SafeUnion { enum { INT, FLOAT, STRING } type; union { int int_val; float float_val; char *str_val; } data; }; void print_safe_union(struct SafeUnion *su) { switch (su->type) { case INT: printf("%d\n", su->data.int_val); break; case FLOAT: printf("%f\n", su->data.float_val); break; case STRING: printf("%s\n", su->data.str_val); break; } }
Important Considerations:
-
Simultaneous Access Issues
cunion Data { int i; float f; }; union Data d; d.i = 10; d.f = 3.14; // Overwrites previous value // Accessing d.i now is undefined behavior -
Endianness Dependency
cunion EndianTest { int value; char bytes[4]; }; union EndianTest test; test.value = 1; if (test.bytes[0] == 1) { printf("Little Endian\n"); } else { printf("Big Endian\n"); } -
Initialization
cunion Data { int i; float f; }; union Data d1 = {10}; // Initialize first member union Data d2 = {.f = 3.14}; // Designated initializer