union
A data structure in which multiple members share the same memory region. It is used to interpret the same data as different types, or to reduce memory usage. The size of a union equals the size of its largest member.
Syntax
// Define a union type.
union UnionTagName {
type memberName1;
type memberName2;
};
// Declare a union variable.
union UnionTagName variableName;
// Access a member (same notation as struct).
variableName.memberName;
pointer->memberName;
// Initialization can only target the first member (C89).
// C99 and later allow designated initializers.
union UnionTagName variableName = {.memberName = value};
union vs. struct
| Item | struct | union |
|---|---|---|
| Memory | Allocates the total size of all members (plus padding). | Allocates only enough space for the largest member. |
| Access | All members can be accessed independently. | Only the last written member holds a valid value. |
| Use case | Used to group multiple pieces of data together. | Used to interpret the same memory as different types. |
Sample Code
#include <stdio.h>
#include <stdint.h>
// A union that interprets a number as different types.
union Number {
int i;
float f;
unsigned char bytes[4];
};
// Tagged union: tracks which member is active using an enum.
typedef enum { TYPE_INT, TYPE_DOUBLE, TYPE_STRING } ValueType;
typedef struct {
ValueType type;
union {
int i_val;
double d_val;
char s_val[64];
} data;
} Value;
void print_value(const Value *v) {
switch (v->type) {
case TYPE_INT: printf("int: %d\n", v->data.i_val); break;
case TYPE_DOUBLE: printf("double: %f\n", v->data.d_val); break;
case TYPE_STRING: printf("string: %s\n", v->data.s_val); break;
}
}
int main(void) {
union Number n;
// Write as int.
n.i = 42;
printf("int value: %d\n", n.i); // Prints "int value: 42".
// Writing as float invalidates the int value.
n.f = 3.14f;
printf("float value: %f\n", n.f);
// View the same memory as a byte array (useful for checking endianness).
n.i = 1;
printf("bytes[0] = %u\n", n.bytes[0]); // Prints "1" on a little-endian system.
// The size equals the size of the largest member.
printf("Size of union Number: %zu bytes\n", sizeof(union Number));
// Use a tagged union to handle variant data.
Value v1 = {TYPE_INT, {.i_val = 100}};
Value v2 = {TYPE_DOUBLE, {.d_val = 3.14}};
print_value(&v1); // Prints "int: 100".
print_value(&v2); // Prints "double: 3.140000".
return 0;
}
Overview
The defining characteristic of a union is that all its members share the same memory address, allowing a single variable to be interpreted as multiple types. Unions are commonly used in low-level byte manipulation such as reading hardware registers or parsing network packets.
Reading a member other than the last one written is "undefined behavior" according to the C standard. However, reading byte representations through an unsigned char member is explicitly permitted by the standard. Use the tagged union pattern when you need to safely work with multiple types.
For a related data structure where all members are independent, use struct. To enumerate a set of related constants, see enum.
If you find any errors or copyright issues, please contact us.