Поделиться через


Проблемы с упаковкой компилятора C

Уровни упаковки одинаково влияют на расположение памяти типов как для MIDL, так и для компилятора Microsoft C/C++. В средах сборки Майкрософт, таких как среда сборки, определенная в VC++ или пакете средств разработки программного обеспечения платформы (SDK), уровень упаковки по умолчанию для компиляторов MIDL и C/C++ одинаков; Уровень упаковки по умолчанию для 32-разрядных и 64-разрядных сред сборки Windows — 8.

Естественное выравнивание

Для типов в памяти выравнивание по умолчанию совпадает с естественным выравниванием.

  • Базовый тип, например short, float и __int64, и указатель выравнивается естественным образом, если его представление начинается с адреса, который имеет размер по модулю. Все поддерживаемые в настоящее время базовые типы имеют размеры 1, 2, 4 или 8. Размер указателей — 4 в 32-разрядных средах и 8 в 64-разрядных средах.
  • Составной тип выравнивается естественным образом, если каждый из его компонентов выравнивается естественным образом относительно начала типа и если между компонентами нет ненужных пробелов (заполнение). Составные компоненты, такие как поля или элементы, рекурсируются в компоненты указателя или базового типа.

Простое правило, помогающее запомнить это поведение, заключается в том, что естественное выравнивание типа равно самым большим выравниваниям его компонентов.

Между выравниванием и размером памяти типа в таких языках, как C или C++ и IDL, существует связь, выраженная оператором sizeof(). Размер кратен выравниванию (минимальное число, охватывающее тип). Это следует из представления массива в памяти.

Естественное выравнивание имеет важное значение, так как доступ к несогласованным данным может вызвать исключение в некоторых системах. Данные могут быть помечены для безопасной манипуляции при неправильной настройке, но обычно это связано с ограничением скорости, которое может быть значительным на некоторых платформах.

Примечание

В памяти объекты типов с естественным выравниванием n гарантированно будут правильно выровнены при размещении по адресам, кратным n.

 

Упаковка и выравнивание

Указание уровня упаковки, превышающего естественное выравнивание типа, не изменяет выравнивание типа. При указании уровня упаковки меньше естественного выравнивания тип уменьшается до уровня упаковки. В результате упакованные типы могут размещаться в памяти по адресам, которые кратны уровню упаковки (уменьшенное выравнивание), не вызывая неправильного выравнивания. Это влияет как на простые типы, так и на типы компонентов. Для составных типов может повлиять внутренняя структура типа, так как уменьшенное выравнивание компонентов может изменить размер отбивки, необходимый для правильного выравнивания компонентов, тем самым уменьшая размер типа.

Простое правило, помогающее запомнить это поведение, заключается в том, что новое выравнивание упакованного типа меньше уровня упаковки и его естественное выравнивание. Размер типа кратен новому выравниванию. Оператор sizeof() возвращает уменьшенный размер для упакованных типов.

Например, при уровне упаковки 2 значение long выравнивается на 2 и, следовательно, может размещаться по любому четному адресу, а не только по адресам, которые кратны 4, как в случае естественного выравнивания. Структура с коротким и длинным, упакованным в 2, не нуждается во внутреннем разрыве между коротким и следующим длинным, который был необходим для естественного выравнивания; следовательно, не только структура теперь выровнена на 2, она также имеет ее размер уменьшен с 8 до 6.

В качестве примера рассмотрим составной тип, состоящий из 1-байтового символа, целого числа длиной 4 байта и 1-байтового символа:

struct mystructtype 
{    
    char c1;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
    long l2;  /* requires 4 bytes */
    char c3;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
 } mystruct;

Эта структура естественным образом выровнена по 4 и имеет естественный размер 12.

Для уровня упаковки 4 или выше структура структуры выравнивается по значению 4 и sizeof(struct mystructtype) равна 12. Структура будет неправильно настроена, если она находится в памяти по адресу, который не кратен 4.

Для уровня упаковки 2 структура выравнивается по 2, а ее размер равен 8. Структура, упакованная с уровнем 2, будет неправильно настроена, если она находится в памяти по адресу, который не кратен 2.

Для уровня упаковки 1 структура выравнивается по 1, а ее размер равен 6. Структура, упакованная с уровнем 1, может быть размещена в любом месте, не вызывая ошибку неправильного выравнивания.

/Zp

/Пакет