По моему опыту, есть два места, где мы хотим использовать uint8_t для обозначения 8 бит (и uint16_t и т. Д.) И где мы можем иметь поля размером менее 8 бит. В обоих случаях пространство имеет значение, и нам часто приходится смотреть на необработанный дамп данных при отладке и иметь возможность быстро определить, что оно представляет.
Первый - в РЧ протоколах, особенно в узкополосных системах. В этой среде нам может понадобиться собрать как можно больше информации в одно сообщение. Второй - во флэш-памяти, где у нас может быть очень ограниченное пространство (например, во встроенных системах).
В обоих случаях мы можем использовать упакованную структуру данных, в которой компилятор позаботится о упаковке и распаковке для нас:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
Какой метод вы используете, зависит от вашего компилятора. Вам также может потребоваться поддержка нескольких разных компиляторов с одинаковыми заголовочными файлами. Это происходит во встроенных системах, где устройства и серверы могут быть совершенно разными - например, у вас может быть устройство ARM, которое взаимодействует с сервером Linux x86.
Есть несколько предостережений с использованием упакованных структур. Самое важное, что вы должны избегать разыменования адреса участника. В системах с выровненными по многобайтовым словам словами это может привести к смещенному исключению - и coredump.
Некоторые люди также будут беспокоиться о производительности и утверждают, что использование этих упакованных структур замедлит работу вашей системы. Это правда, что за кулисами компилятор добавляет код для доступа к невыровненным элементам данных. Это можно увидеть, посмотрев код сборки в вашей среде IDE.
Но поскольку упакованные структуры наиболее полезны для связи и хранения данных, данные могут быть извлечены в неупакованное представление при работе с ним в памяти.
Обычно нам вообще не нужно работать со всем пакетом данных в памяти.
Вот некоторые соответствующие обсуждения:
Pragma Pack (1), ни __attribute__ ((выровненный (1))) работает
Является ли __attribute gcc __ ((упакованный)) / #pragma pack небезопасным?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html