Есть у нас, допустим структура.
struct my_struct{ int a; char b; int c; }; |
Но если на разных платформах ( например avr и arm ) выполнить следующий код
printf("размер структуры %u\r\n", sizeof( struct my_struct ) ); |
то мы получим разные результаты. Для arm размер структуры равен 12, а для avr равен 5. Почему?
На первый взгляд, потому, что переменные типа int на различных платформах имеют разную разрядность. Для arm это 4 байта, для avr 2 байта.
Перепишем нашу структуру.
struct my_struct{ short a; char b; short c; }; |
Тип short имеет размер 2 байта на всех платформах.
Но мы опять получаем разный размер структуры, для arm 6 байт, для avr 5 байт.
Дело в том что компилятор gcc (да и большинство других) по умолчанию выравнивает поля структуры (дополняет неиспользуемыми байтами) в соответствии с следующим правилом: каждое поле выравнивается по адресу, кратному размеру данного поля. Поле типа int на 32-битной системе будет выровнено по границе 4 байт, short по границе 2 байта. Поля типа char не выравниваются. Размер структуры выравнивается до размера, кратному размеру его максимального элемента.
Но как нам быть, если мы хотим передать структуру с одной платформы на другую.
Устранить поведение по умолчанию и убрать выравнивание можно если указать
атрибут packed при описании структуры, директива компилятора #pragma pack(1) также может использоваться для этой цели
struct my_struct{ short a; char b; short c; }__attribute__((__packed__ )); |
В этом случае «пустоты», связанные с выравниванием, исчезают и размер структуры на разных платформах становиться одинаковым.
Если у нас много экземпляров структуры, то отключив выравнивание можно сэкономить память. Отрицательной стороной отключения выравнивания является то, что при этом увеличивается программный код и время необходимые для обработки структур.
Спасибо,классная статья!
Пожалуйста! ;)
Особенно это актуально когда делаешь обмен по UARTу или чему то подобному между разными платформами (и описываешь команды структурами), иначе могут возникнуть чудеса.
Для блоков можно делать так
#pragma push() // запоминаем текущее выравнивание
#pragma pack(1)
..
.. тут всякие структуры
..
#pragma pop() // восстанавливаем выравнивание
Это разве статья, так заметка. А всё таки char будет выравниваться или нет?