Использование объединений в C для эффективной упаковки и распаковки данных
Использование объединений в C для эффективной упаковки и распаковки данных
Объединения предоставляют мощный, экономный по памяти способ переинтерпретировать одни и те же байты как разные типы данных. Изначально предназначенные для совместного использования памяти между взаимоисключающими переменными, в современном C объединения часто применяют для упаковки, распаковки и type punning — особенно при работе с последовательными протоколами или низкоуровневым обменом данными.
Как объединение разделяют память
Все члены объединения разделяют одну область памяти. Размер объединения определяется самым большим членом, и каждый член начинается по одному адресу.
union { uint16_t word; struct { uint8_t byte1; uint8_t byte2; }; } u1;
Здесь word занимает два байта, а вложенная структура разбивает их на byte1 и byte2. Расположение можно представить так:

Упаковка двух байт в 16-битное слово
Чтобы объединить два 8-битных значения x и y в 16-битное слово, присвойте их членам структуры, а затем прочитайте член word:
u1.byte1 = y; u1.byte2 = x; uint16_t packed = u1.word;
Такой «type punning» прост, но зависит от порядка байтов процессора.
Порядок байтов (endianness) имеет значение
В little-endian системах младший байт хранится первым, в big-endian — старший. Рассмотрим последовательность 0x01020304:

Простой тест на little-endian машине дает:
#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; }
Вывод: Word is: 0X4321 — подтверждает little-endian. На big-endian том же код выдал бы 0X2143.
Битовая альтернатива: упаковка, независимая от endianness
Сдвиги и маски дают переносимый способ построить 16-битное значение:
uint16_t word2 = (((uint16_t)byte3) << 8) | ((uint16_t)byte4);
Сравнение обоих методов:
#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; }
На big-endian: Word1 is: 0X2143, Word2 is: 0X2143. На little-endian: Word1 is: 0X4321, Word2 is: 0X2143. Битовый подход гарантирует одинаковый результат на любой архитектуре.
Практический пример: передача float по UART
Последовательные линии передают по одному байту. Чтобы отправить 32-битный float, можно использовать объединение, чтобы представить float как массив из четырех байт:
union buffer { float f; struct { uint8_t byte[4]; }; };
Передающая сторона:
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);
Вывод: The received data is: 5.500000. Объединение чисто разделяет байтовое представление и значение с плавающей точкой, делая код читаемым и поддерживаемым.

Выводы
- Объединения позволяют type punning, но результат зависит от endianness.
- Битовые операторы дают переносимую, архитектурно-независимую упаковку.
- Для ясности и сопровождаемости многие разработчики всё равно предпочитают объединения во встраиваемых системах.
- Объединения блестят при передаче произвольных структур данных по байто-ориентированным линиям.
Чтобы узнать больше о C, объединениях и встраиваемых системах, посмотрите полный список статей.
Встроенный
- Семафоры в Nucleus RTOS: Утилитарные сервисы и структуры данных
- Армия США развивает состояние-ориентированное обслуживание с инновационными датчиками и предиктивной анали…
- Как IIoT и аналитика данных трансформируют EHS: повышение безопасности, эффективности и экономии
- Создание ответственного и надежного AI: руководство по объяснимости, подотчетности и этике
- Fog Computing: трансформация потока данных IoT и снижение нагрузки на облако
- Объединения в C (union): эффективное использование памяти для разных типов данных
- Раскрытие видимости цепочки поставок: решающая роль данных и контекста
- Революция в управлении автопарками: интеграция ИИ и IoT для более умных операций
- Промышленный AIoT: слияние ИИ и IoT для инноваций Индустрии 4.0
- Litmus и Oden запускают интегрированные IIoT решения для Smart Manufacturing