Компиляторы могут выполнять выравнивание структуры данных для целевой архитектуры, если это необходимо. Это может быть сделано исключительно для улучшения производительности во время выполнения приложения или в некоторых случаях требуется процессор (т. Е. Программа не будет работать, если данные не выровнены).
Например, для большинства (но не всех) команд SSE2 требуются данные для выравнивания по 16-байтовой границе. Проще говоря, все в памяти компьютера имеет адрес. Скажем, у нас есть простой массив удваивается, например:
double data[256];
Для того, чтобы использовать SSE2 инструкции, требующие согласования 16-байтовый, необходимо убедиться, что адрес &data[0]
кратен 16.
Требования к выравниванию отличаются от одной архитектуры к другой. На x86_64 рекомендуется, чтобы все структуры размером более 16 байт выровнены по 16-байтовым границам. В общем, для лучшей производительности, выровнять данные следующим образом:
- Юстировка 8-битовые данные по любому адресу
- Align 16-битные данные, которые должны содержаться в пределах выровненной четыре байта слова
- Юстировка 32 -разрядные данные так, что его базовый адрес является кратным четырем
- Юстировки 64-битовых данных таким образом, что его базовый адрес является кратным восьми
- Юстировки 80-битовых данных таким образом, что его базовый адрес является кратным шестнадцати
- Выровняйте 128-битные данные так, чтобы их базовые e адрес является кратным шестнадцати
Интересно, что большинство процессоров x86_64 будут работать как с выровненными, так и с выровненными данными. Однако, если данные не выровнены должным образом, CPU выполняет код значительно медленнее.
Когда компилятор учитывает это, он может неявно выравнивать элементы структуры и повлиять на его размер. Например, предположим, что мы имеем структуру, как это:
struct A {
char a;
int b;
};
Предполагая, x86_64, размер int
составляет 32 бит или 4 байта. Поэтому рекомендуется всегда делать адрес b
кратным 4. Но поскольку размер поля a
составляет всего 1 байт, это будет невозможно.Таким образом, компилятор добавит 3 байт заполнения между a
и b
неявно:
struct A {
char a;
char __pad0[3]; /* This would be added by compiler,
without any field names - __pad0 is for
demonstration purposes */
int b;
};
Как компилятор делает это зависит не только от компилятора и архитектур, но и на настройках компилятора (флаги) вы передаете компилятор. Это поведение также может быть затронуто с помощью специальных языковых конструкций. Например, можно попросить компилятор не выполнять никаких отступов с packed
атрибута, как это:
struct A {
char a;
int b;
} __attribute__((packed));
В вашем случае, mingw32-gcc.exe
просто добавили 7 байт между c
и d
для выравнивания d
8 границы байта. В то время как gcc 4.6.3 на Ubuntu добавила только 3, чтобы выровнять d
на границе 4 байта.
Если вы не выполняете некоторые оптимизации, пытаясь использовать специальный расширенный набор инструкций или не имеете конкретных требований к своим структурам данных, я бы рекомендовал вам не зависеть от конкретного поведения компилятора и всегда предполагать, что не только ваша структура может получить он может дополняться друг от друга между архитектурами, компиляторами и/или разными версиями компилятора. В противном случае вам потребуется полуавтоматически обеспечить выравнивание данных и размеры структуры с помощью атрибутов и параметров компилятора и убедиться, что все это работает на всех компиляторах и платформах, на которые вы нацеливаетесь, с помощью модульных тестов или, возможно, даже static assertions.
Для получения дополнительной информации, пожалуйста, проверьте:
Надеется, что это помогает. Удачи!
Как минимизировать отступы:
Это всегда хорошо, чтобы все ваши элементы этой структуры правильно выровнены и в то же время сохранить свой размер структуры разумно. Рассмотрим эти 2 структура варианты с членами rearanged (теперь предположим, SizeOf полукокса, короткие, Int, долго, долго долго, чтобы быть 1, 2, 4, 4, 8, соответственно):
struct A
{
char a;
short b;
char c;
int d;
};
struct B
{
char a;
char c;
short b;
int d;
};
Обе структуры должны сохранить те же данные, но в то время как SizeOf (структура A) будет 12 байт, SizeOf (структура в) будет 8 из-за хорошо, хотя отказа члена порядок, который устраняется неявное заполнение:
struct A
{
char a;
char __pad0[1]; // implicit compiler padding
short b;
char c;
char __pad1[3]; // implicit compiler padding
int d;
};
struct B // no implicit padding
{
char a;
char c;
short b;
int d;
};
Перегруппировка члены структуры могут быть подвержены ошибкам с увеличением количества членов. Для того, чтобы сделать его меньше ошибок - поместить самый длинный в начале и кратчайшим в конце:
struct B // no implicit padding
{
int d;
short b;
char a;
char c;
};
неявной обивка в конце stuct:
В зависимости от компилятора, настройки платформы и т.д. используется вами может заметить, что компилятор добавляет дополнение не только к элементам структуры, но и к концу (т. е. после последнего элемента).Под строкой:
struct abcd
{
long long a;
char b;
};
может занимать 12 или 16 байт (худшие компиляторы позволят ему иметь 9 байтов). Это дополнение можно легко упустить, но очень важно, если ваша структура будет элементом массива. Он будет гарантировать, что ваш член в последующих ячейках ячеек/элементов будет правильно выровнен.
Заключительные и случайные мысли:
Он никогда не повредит (и может реально сэкономить) вам, если - при работе с структурами - вы будете следовать этим советам:
- Не полагайтесь на компилятор чередуйте элементы структуры с правильным заполнением.
- Убедитесь, что ваша структура (если внешний массив) выровнена с границей, требуемой ее самым длинным элементом.
- Удостоверьтесь, что вы упорядочиваете элементы структуры так, чтобы самые длинные были размещены первым и последним членом.
- Убедитесь, что вы явно вставляете свою структуру (если необходимо), чтобы при создании массива структур каждый член структуры имел правильное выравнивание.
- Убедитесь, что массивы ваших структур правильно выровнены, так как хотя вашей структуре может потребоваться 8-байтовое выравнивание, ваш компилятор может выровнять ваш массив с 4-байтовой границей.
Проверить это [размер типов данных] (http://stackoverflow.com/questions/14821738/size-of-basic-data-types-in-c) –
Структура упаковки различна в разных составителей. –