Structures and unions in Embedded C both group different data types, but they differ mainly in how memory is allocated.
Structures allocate separate memory for each member, while unions share the same memory location among their members.
Structures suit related data stored together, while unions are useful for memory optimization and multiple representations of the same storage.
Structures and unions are important user-defined data types in C programming and are widely used in embedded systems. Although both allow programmers to group different types of data under one name, they handle memory allocation and data storage differently. Understanding the difference between structures and unions in C is especially important for embedded developers because microcontrollers often have limited RAM, flash memory, and processing resources. In this guide, we will explain structures vs unions in Embedded C, how they allocate memory, their differences, practical examples, and when to use each one in embedded systems.
Both structures and unions allow multiple variables of different data types to be grouped together.
For example, an embedded application may need to store information such as:
Instead of declaring each variable separately, C allows developers to organize related variables using a structure or union.
The key difference is how memory is allocated.
This difference makes structures useful when multiple values need to be stored at the same time, while unions can be useful when only one representation of data is required at a time.
A structure in C is a user-defined data type that groups multiple variables, potentially of different data types, into a single unit.
struct Sensor
{
int sensor_id;
float temperature;
char status;
};A structure variable can then be created:
struct Sensor sensor1;Values can be assigned using the dot operator:
sensor1.sensor_id = 101;
sensor1.temperature = 28.5;
sensor1.status = 'A';Here, all three members have their own storage.
The structure can therefore hold the sensor ID, temperature, and status simultaneously.
One of the most important characteristics of a structure is that each member gets its own storage.
Consider:
struct Device
{
int id;
float voltage;
char status;
};Conceptually, memory looks like:
+------------------+
| id |
+------------------+
| voltage |
+------------------+
| status |
+------------------+The actual size of the structure may be larger than the simple sum of the member sizes because of padding and alignment added by the compiler.
For example, developers should not always assume:
The compiler may insert padding to satisfy alignment requirements.
This is particularly important when designing memory-efficient structures for microcontrollers.
A union is another user-defined data type in C. Unlike a structure, all members of a union share the same memory location.
union SensorData
{
int value;
float temperature;
char status;
};A union variable can be declared as:
union SensorData data;The same memory area is used by value, temperature, and status.
Conceptually:
+-------------------------+
| Shared Memory |
| int / float / char |
+-------------------------+Only one member should generally be treated as the currently active representation of the stored data.
The size of a union is generally determined by its largest member, subject to the alignment requirements of the implementation.
For example:
union Data
{
int a;
float b;
char c;
};If int and float each require 4 bytes while char requires 1 byte, the union will typically require enough storage for the largest member.
Conceptually:
Union Data
+------------------+
| |
| Shared Memory |
| |
+------------------+The same memory is reused when accessing different union members.
This makes unions useful when memory efficiency matters and different interpretations of the same data are required.
The main difference between a structure and a union is memory allocation.
| Feature | Structure | Union |
| Memory allocation | Separate memory for members | Shared memory |
| Multiple members stored simultaneously | Yes | No, members overlap |
| Size | Influenced by all members, padding and alignment | Influenced mainly by largest member and alignment |
| Memory usage | Usually higher | Usually lower |
| Access | Members retain their stored values | Writing one member can affect the interpretation of others |
| Typical use | Grouping related data | Shared representation of data |
| Embedded use | Sensor/device configurations | Protocol data, flags, alternative representations |
Memory usage is one of the biggest reasons embedded developers need to understand the difference between structures and unions.
Consider:
struct Data
{
int id;
float value;
};Both id and value need to be stored.
With a structure:
+----------+
| id |
+----------+
| value |
+----------+Both values exist independently.
Now consider:
union Data
{
int id;
float value;
};The members share the same storage:
+----------------+
| Shared Memory |
+----------------+If the application only needs one representation at a time, a union can reduce the amount of storage required.
However, developers should not automatically replace every structure with a union. The correct choice depends on how the data is used.
Consider a device that stores information about a sensor.
Using a structure:
struct Sensor
{
int sensor_id;
float temperature;
};The application can store both:
sensor.sensor_id = 101;
sensor.temperature = 27.5;Both values remain available.
With a union:
union SensorData
{
int sensor_id;
float temperature;
};The same memory is used for both members.
For example:
data.sensor_id = 101;and later:
data.temperature = 27.5;The second assignment uses the same storage.
Therefore, a union should be used when overlapping representations are intentional.
Structures are useful when multiple pieces of information must exist simultaneously.
Embedded applications frequently collect multiple values from sensors.
struct SensorData
{
float temperature;
float humidity;
int sensor_id;
};Here, all values are required at the same time, making a structure appropriate.
A device configuration can contain multiple parameters:
struct DeviceConfig
{
int baud_rate;
char device_id;
int timeout;
};Each member represents a different configuration value.
Structures can be used to group settings related to communication interfaces, timers, GPIOs, and other peripherals.
Embedded applications often need to maintain multiple related states:
struct SystemStatus
{
int temperature;
int battery_level;
char error_code;
};A structure allows all these values to coexist.
Unions are particularly useful when the same memory needs to represent data in different ways.
Communication protocols often transmit raw bytes that need to be interpreted in different ways.
A union can provide multiple views of the same storage, when used in a manner appropriate to the C implementation and protocol requirements.
Microcontrollers with limited RAM may benefit from unions when several pieces of data are mutually exclusive.
For example:
union CommandData
{
int motor_speed;
int led_pattern;
int error_code;
};If the application only needs one command type at a time, the same storage can be reused.
Unions are sometimes used alongside structures and bit-fields to provide different views of hardware-related data.
For example:
union StatusRegister
{
unsigned char value;
struct
{
unsigned char ready : 1;
unsigned char error : 1;
unsigned char busy : 1;
unsigned char reserved : 5;
} bits;
};This can allow the programmer to access the complete register value or individual fields.
However, hardware register definitions should follow the microcontroller manufacturer’s documentation and compiler requirements.
Memory optimization is an important part of Embedded C programming.
Microcontrollers may have significantly fewer resources than desktop computers. Therefore, developers often need to carefully consider:
A union can reduce memory usage when several data representations are mutually exclusive.
For example:
union CommunicationData
{
int command;
float sensor_value;
char message[4];
};The members share storage.
However, using a union does not automatically make an embedded application more efficient. Poor data design can introduce bugs or make the code difficult to understand.
Memory optimization should always be based on the application’s actual requirements.
One important topic related to structure vs union memory usage is padding.
Consider:
struct Example
{
char a;
int b;
char c;
};You might expect the size to be:
But the compiler may add padding between members or at the end of the structure to satisfy alignment requirements.
Therefore, sizeof(struct Example) may return a value larger than 6 bytes depending on the compiler, target architecture, ABI, and compiler options.
For embedded developers, understanding alignment and padding is important when:
Embedded systems frequently communicate using protocols such as:
Data received from these interfaces is often represented as bytes.
For example:
unsigned char buffer[4];A developer may need to interpret those bytes as an integer or another data type.
A union can provide an alternative view of the same storage, but developers must be careful about endianness, alignment, object representation, strict aliasing, and portability.
For portable embedded software, explicitly copying bytes into an appropriately typed object using well-defined operations is often safer than relying on assumptions about memory representation.
Structures and unions do not have a universal performance advantage over one another.
Performance depends on:
A union’s main advantage is shared storage, not automatically faster execution.
Similarly, structures are not inherently slow. They provide a straightforward way to organize related data.
For embedded development, the focus should be on choosing the data type that correctly represents the application’s requirements.
Do not assume that the size of a structure is always the exact sum of its member sizes. Padding and alignment can change the final size.
A union does not provide independent storage for each member. Writing to one member changes the shared storage.
When unions are used for communication data, the byte order of the target system matters.
Memory savings should not come at the expense of correctness and maintainability.
Embedded C programs depend heavily on the target architecture and compiler implementation.
Code involving memory representation, bit-fields, packed structures, and type punning should therefore be designed carefully.
The answer depends on how the data needs to be stored.
Use a structure when:
Use a union when:
A simple way to remember the difference is:
This topic is also common in Embedded C interview questions.
A typical interview question is:
A concise answer is:
A structure allocates storage for each member, allowing all members to hold values simultaneously. A union stores all members in overlapping storage, so the same memory is reused for different members.
Interviewers may also ask:
Understanding the concepts rather than memorizing definitions is important for answering these questions effectively.
Understanding Structures vs Unions in Embedded C is essential for writing efficient and reliable embedded software.
Structures are primarily used to group related data where each member needs independent storage. Unions allow multiple members to share the same memory, making them useful when different representations are mutually exclusive or when a shared representation is intentional.
For embedded developers, the decision should not be based only on memory size. Correctness, portability, alignment, memory layout, maintainability, and the requirements of the target microcontroller should also be considered.
Once you understand structures, unions, padding, alignment, and memory layout, you will have a stronger foundation for working with Embedded C, microcontrollers, communication protocols, peripheral drivers, and memory-constrained embedded applications.
The main difference is memory allocation. A structure gives each member its own storage, while a union allows all members to share the same storage.
A union often requires less storage when its members are mutually exclusive because they share memory. The exact size depends on the members, alignment, and implementation.
Yes. A structure can contain a union as one of its members.
struct Packet
{
int type;
union
{
int value;
float measurement;
} data;
};
This pattern can be useful when a packet contains a common header and one of several possible payload formats.
Yes. A union can also contain a structure as one of its members.
union Data
{
int value;
struct
{
char id;
char status;
} info;
};
Indian Institute of Embedded Systems – IIES