Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial Internet of Things >> Embedded

Using Unions in C for Efficient Data Packing and Unpacking

Using Unions in C for Efficient Data Packing and Unpacking

Unions provide a powerful, memory‑efficient way to reinterpret the same bytes as different data types. While originally intended for shared memory among mutually exclusive variables, modern C programmers often use unions for data packing, unpacking, and type punning—especially when handling serial protocols or low‑level communication.

How a Union Shares Memory

All members of a union share the same memory region. The largest member determines the size of the union, and every member starts at the same address.

union {
    uint16_t   word;
    struct {
        uint8_t byte1;
        uint8_t byte2;
    };
} u1;

Here, word occupies two bytes, while the nested structure splits those two bytes into byte1 and byte2. The layout can be visualized as:

Using Unions in C for Efficient Data Packing and Unpacking

Packing Two Bytes Into a 16‑bit Word

To combine two 8‑bit values x and y into a 16‑bit word, assign them to the structure members and then read the word member:

u1.byte1 = y;
u1.byte2 = x;
uint16_t packed = u1.word;

This “data punning” is straightforward but depends on the processor’s byte order.

Processor Endianness Matters

Little‑endian systems store the least significant byte first, while big‑endian systems store the most significant byte first. Consider the sequence 0x01020304:

Using Unions in C for Efficient Data Packing and Unpacking

Running a simple test on a little‑endian machine yields:

#include <stdio.h>
#include <stdint.h>

int main() {
    union {
        struct { uint8_t byte1; uint8_t byte2; };
        uint16_t word;
    } u1;
    u1.byte1 = 0x21;
    u1.byte2 = 0x43;
    printf("Word is: %#X\n", u1.word);
    return 0;
}

Output: Word is: 0X4321—confirming little‑endian storage. On a big‑endian target the same code would output 0X2143.

Bitwise Alternative: Endianness‑Independent Packing

Shifting and masking provide a portable way to build a 16‑bit value:

uint16_t word2 = (((uint16_t)byte3) << 8) | ((uint16_t)byte4);

Comparing both methods:

#include <stdio.h>
#include <stdint.h>

int main() {
    union {
        struct { uint8_t byte1; uint8_t byte2; };
        uint16_t word1;
    } u1;
    u1.byte1 = 0x21;
    u1.byte2 = 0x43;
    printf("Word1 is: %#X\n", u1.word1);

    uint8_t byte3 = 0x21, byte4 = 0x43;
    uint16_t word2 = (((uint16_t)byte3) << 8) | ((uint16_t)byte4);
    printf("Word2 is: %#X\n", word2);
    return 0;
}

On a big‑endian processor: Word1 is: 0X2143, Word2 is: 0X2143. On a little‑endian processor: Word1 is: 0X4321, Word2 is: 0X2143. The bitwise approach guarantees consistent results across architectures.

Practical Example: Sending a Float Over UART

Serial links typically transmit one byte at a time. To send a 32‑bit float, we can use a union to view the float as an array of four bytes:

union buffer {
    float f;
    struct { uint8_t byte[4]; };
};

Transmit side:

union buffer tx;
union buffer rx;
float f1 = 5.5f;

tx.f = f1;
for (int i = 0; i < 4; ++i) {
    // send tx.byte[i] over UART
    rx.byte[i] = tx.byte[i]; // Simulated receive
}

printf("The received data is: %f\n", rx.f);

Output: The received data is: 5.500000. The union cleanly separates the byte representation from the floating‑point value, making the code readable and maintainable.

Using Unions in C for Efficient Data Packing and Unpacking

Takeaways

To explore more about C, unions, and embedded systems, browse my complete list of articles.

Embedded

  1. CyrusOne Enhances User Experience with Real‑Time Application Monitoring
  2. Beyond Conventional Data Loggers: A Superior Solution for PLC Data Acquisition
  3. Embedded C Unions Explained: Efficient Memory Sharing & Messaging
  4. U.S. Army Advances Condition‑Based Maintenance with Innovative Sensors and Predictive Analytics
  5. How IIoT & Data Analytics Transform EHS: Boosting Safety, Efficiency, and Savings
  6. Fog Computing Explained: Transforming IoT Data Flow and Reducing Cloud Load
  7. C Unions Explained: Efficient Memory Management for Multiple Data Types
  8. Harnessing OCR, AI, and RPA to Unlock Advanced Data Insights
  9. Industrial DataOps: Driving Competitive Edge with Advanced Analytics in Industry 4.0
  10. Accelerate Business Insights with Automated Data Science & Machine Learning Solutions