Why do we need C Unions?
Unions are often used to convert between the binary representations of integers and floats:
union{ int i; float f;} u;// Convert floating-point bits to integer:u.f = 3.14159f;printf("As integer: %08x\n", u.i);
Although this is technically undefined behavior according to the C standard (you're only supposed to read the field which was most recently written), it will act in a well-defined manner in virtually any compiler.
Unions are also sometimes used to implement pseudo-polymorphism in C, by giving a structure some tag indicating what type of object it contains, and then unioning the possible types together:
enum Type { INTS, FLOATS, DOUBLE };struct S{ Type s_type; union { int s_ints[2]; float s_floats[2]; double s_double; };};void do_something(struct S *s){ switch(s->s_type) { case INTS: // do something with s->s_ints break; case FLOATS: // do something with s->s_floats break; case DOUBLE: // do something with s->s_double break; }}
This allows the size of struct S
to be only 12 bytes, instead of 28.
Unions are particularly useful in Embedded programming or in situations where direct access to the hardware/memory is needed. Here is a trivial example:
typedef union{ struct { unsigned char byte1; unsigned char byte2; unsigned char byte3; unsigned char byte4; } bytes; unsigned int dword;} HW_Register;HW_Register reg;
Then you can access the reg as follows:
reg.dword = 0x12345678;reg.bytes.byte3 = 4;
Endianness (byte order) and processor architecture are of course important.
Another useful feature is the bit modifier:
typedef union{ struct { unsigned char b1:1; unsigned char b2:1; unsigned char b3:1; unsigned char b4:1; unsigned char reserved:4; } bits; unsigned char byte;} HW_RegisterB;HW_RegisterB reg;
With this code you can access directly a single bit in the register/memory address:
x = reg.bits.b2;
Low level system programming is a reasonable example.
IIRC, I've used unions to breakdown hardware registers into the component bits. So, you can access an 8-bit register (as it was, in the day I did this ;-) into the component bits.
(I forget the exact syntax but...) This structure would allow a control register to be accessed as a control_byte or via the individual bits. It would be important to ensure the bits map on to the correct register bits for a given endianness.
typedef union { unsigned char control_byte; struct { unsigned int nibble : 4; unsigned int nmi : 1; unsigned int enabled : 1; unsigned int fired : 1; unsigned int control : 1; };} ControlRegister;