По умолчанию для ARM все поля в структурах компилятор C выравнивает на границу 4 байта - это позволяет оптимизировать код, который поддерживает обращение к полям структуры. Если об этом забыть и не учитывать в программе (например, при работе со всеми полями структуры как одним блоком данных), то могут возникать неожиданные ошибки.
Выравнивание - это просто обеспечение кратности адресов определенному числу. Например, "выравнивание полей структуры на 4 байта" означает, что физический адрес каждого поля структуры делится нацело на 4.
По умолчанию в IAR для всех объектов памяти размером от 4 байт и более выравнивание включено. Это очень важно для буферов, работающих с прямым доступом к памяти (PDC) периферии ARM. Начальный адрес буфера памяти, работающий с PDC, должен быть обязательно выровнен на 4. Для работы со структурами протокола USB выравнивание должно быть наоборот выключено. Будьте внимательны, неправильно выбранное выравнивание может быть причиной неприятных ошибок!
В разных версиях IAR Embedded Workbench синтаксис для управления выравниванием может быть устроен по разному. В этой статье рассматриваются два варианта синтаксиса: для IAR версии 4.41A и для IAR версии 5.50.
[IAR 4.41A]
Для управления выравниванием используется специальная директива управления компилятором #pragma pack. По умолчанию, если #pragma pack не указано, то включено выравнивание на границу 32-битного слова (4 байта). Могут быть следующие варианты использования pack:
#pragma pack() //восстанавливает состояние по умолчанию (выравнивание на 32 бита)
#pragma pack(n) //выравнивание на 1, 2, 4, 8 или 16 байт (указывается вместо n)
#pragma pack({push|pop}[,name] [,n])
[IAR 5.50]
Устранить поведение по умолчанию и убрать выравнивание позволяет ключевое слово __packed при объявлении структуры или директивы #pragma pack и #pragma data_alignment для модуля. В этом случае "пустоты", связанные с выравниванием, в структуре исчезают (экономится память, и не надо помнить о выравнивании), но несколько увеличивается код обработки структур. Пример использования __packed:
typedef __packed struct _Params
{
u32 paramseed;
u32 versionARM;
u32 versionDSP;
u8 backlight;
u8 contrast;
u8 minContrast;
u8 maxContrast;
char ProducerName[15];
char ProducerURL[15];
char ProducerEmail[15];
u32 usbProdID;
u32 usbVendorID;
u16 CRC;
} TParams;
Будьте внимательны с размещением буферов в упакованной (__packed) структуре, если эти буфера работают с прямым доступом к памяти (DMA), лучше этого избегайте (определяйте буфер отдельно от упакованной структуры). Если все-таки решили поместить буфер в структуру с атрибутом __packed, то размещайте буфер в начале структуры, что гарантирует выравнивание его адреса на 4. Тогда прямой доступ к памяти будет всегда работать корректно.
[Ссылки]
1. Как выровнять (align) размер памяти на 4 байта? |