Question.1
A union contains a uint32_t and a byte array:
union Data {
uint32_t word;
uint8_t bytes[4];
};
Data d;
d.word = 0x11223344;
printf("0x%02X", d.bytes[0]); On a little-endian ARM Cortex-M, what is printed?
A Struct is like a House where every member gets their own room.
A Union is like a Fitting Room. Only one person (member) can use it at a time.
In a Union, all members share the same memory address. Writing to one member overwrites the others.
Size: The size of a Union is equal to the size of its largest member.
Purpose: To store different types of data in the same spot, or to view the same data in different formats (Type Punning).
Basic Declaration
union PacketData {
uint32_t intValue;
float floatValue;
uint8_t bytes[4];
};
int main() {
PacketData data;
// 1. Store a float
data.floatValue = 3.14f;
// 2. Read it as raw bytes (Common in Drivers)
// data.bytes[0] ... data.bytes[3] now hold the IEEE 754 representation of 3.14
// NOTE: In strict C++, reading the "wrong" member is Undefined Behavior,
// but in Embedded Compilers (GCC/ARM), this is supported and standard practice.
}Anonymous Unions (The Embedded Standard)
Often nested inside structs to provide "Raw vs Bit" access without needing a variable name for the union itself.
struct Register {
union {
uint32_t whole_reg; // Access full 32 bits
struct {
uint32_t enable : 1;
uint32_t mode : 2;
uint32_t error : 1;
uint32_t rsvd : 28;
} bits; // Access specific fields
};
};
Register CTRL;
CTRL.whole_reg = 0x00; // Clear all
CTRL.bits.enable = 1; // Set bit 0 onlyAssume uint32_t i and uint8_t b[4].
Byte Offset | Union Member i (32-bit) | Union Member b (Array) |
|---|---|---|
+0 |
|
|
+1 |
|
|
+2 |
|
|
+3 |
|
|
If you write 0x11223344 to i, b[0] automatically becomes 0x44 (on Little Endian systems).
A. Hardware Register Mapping
This is the most common use case. Vendor header files (like STM32 HAL) use unions to allow you to write to the whole register (regs->CR1 = 0;) or specific bits (regs->CR1_b.EN = 1;) efficiently.
B. Data Serialization (Endianness Handling)
Sending a float over UART or I2C? You can't send a "float". You must send bytes.
A union allows you to simply dump the byte array u.bytes into the UART buffer without messy pointer casting or bit-shifting logic.
union FloatConverter {
float f;
uint8_t b[4];
};
void send_sensor_data(float val) {
FloatConverter u;
u.f = val;
UART_Transmit(u.b, 4); // Sends the raw bytes of the float
}C. Variant Packets (Polymorphic Data)
If a protocol sends different packet types based on a "Message ID", you use a union to hold the payload.
struct Message {
uint8_t type;
union {
struct { int x, y; } gps;
struct { float volt; } battery;
struct { char text[10]; } log;
} payload;
};
// Size of 'payload' is max(sizeof(gps), sizeof(battery), sizeof(log)).
// It does not waste RAM storing all three.std::variant)In high-level C++ (Linux/Desktop), raw unions are considered unsafe because you don't know which type is currently active.
C++17 introduced std::variant, which is a "Type-Safe Union". It remembers what it holds.
Embedded Note: std::variant is often too heavy for small microcontrollers (uses more RAM/Rom). Raw Unions remain the standard for drivers.
Pitfall | Details |
|---|---|
❌ Endianness | Using unions to split Little Endian: Big Endian: |
❌ Constructors | If a Union member has a complex Constructor (like String or Vector), the Union cannot initialize it automatically. C++11 relaxed this, but you must manually call Placement New/Destructors. Avoid complex objects in Unions. |
❌ Type Punning (UB) | The C++ Standard says: "If you write to float, you can ONLY read from float." Reading bytes is technically Undefined Behavior. However, gcc/clang explicitly support this for unions. It works, but know that it's technically non-standard. |
✅ Zero Initialization |
|
Summary Checklist
Use Unions to save RAM when storing mutually exclusive data.
Use Anonymous Unions inside Structs for Register Bitfields.
Be aware of Endianness when using Unions for serialization.
Stick to "POD" (Plain Old Data) types inside unions (int, float, pointers). Avoid Classes.