Рассмотрим следующую программу
#include<iostream>
struct SimpleStructure
{
double obj;
};
struct Composite
{
struct SimpleStructure u;
char ch;
};
int main()
{
using namespace std;
cout << "sizeof(double) : " << sizeof(double) << endl;
cout << "sizeof(struct SimpleStructure) : " << sizeof(struct SimpleStructure) << endl;
cout << "sizeof(struct Composite) : " << sizeof(struct Composite) << endl;
return 0;
}
Когда я скомпилирую выше с g++ -m64 <filename>.cpp
Я получаю следующий вывод
sizeof(double) : 8
sizeof(struct SimpleStructure) : 8
sizeof(struct Composite) : 16
Но тот же код, когда я компилирую с помощью g++ -m32 <filename>.cpp
Я получаю следующий вывод
sizeof(double) : 8
sizeof(struct SimpleStructure) : 8
sizeof(struct Composite) : 12
Почему разница в заполнении в структуре в 32-битном и 64-битном процессах?
На 32-битной платформе alignof(double) == 4
, Увидеть man gcc
:
-malign-double -mno-align-double Control whether GCC aligns "double", "long double", and "long long"variables on a two-word boundary or a one-word boundary. Aligning "double" variables on a two-word boundary produces code that runs somewhat faster on a Pentium at the expense of more memory. On x86-64, -malign-double is enabled by default. Warning: if you use the -malign-double switch, structures containing the above types are aligned differently than the published application binary interface specifications for the x86-32 and are not binary compatible with structures in code compiled without that switch.
Размер структуры кратен выравниванию элемента с наибольшим требованием выравнивания. Здесь такой член имеет тип double
, так sizeof(struct Composite) == N * alignof(double)
,
Что касается стандарта C, то компилятор может выбрать любое выравнивание. Ниже приведено описание того, как используемые мной компиляторы реализовали выравнивание.
Часто выбирается размер слова (32 бита в 32-битной системе, 64 бита в 64-битной системе), поскольку он обычно является эффективным выбором с точки зрения компромисса между использованием памяти и производительностью на целевой платформе. Обычно доступ к памяти можно получить кусками размером в слово, и в инструкциях процессора предполагается, что данные выровнены, поэтому, если данные выровнены, процессору потребуется получить доступ к 2 частям памяти и сместить данные в выравнивание. Это тратит впустую ценные циклы процессора.
Сущности, меньшие, чем размер слова, выровнены по размеру. Слово размером и более крупные объекты выровнены по границам слова.
Элементы структуры выравниваются отдельно, а затем вся структура дополняется и выравнивается так же, как ее самый большой элемент.
Выравнивание по умолчанию часто можно переопределить с помощью прагм. Пожалуйста, обратитесь к документации для вашего компилятора для деталей.
Пример:
/* Override the default alignment and pack everything tight. */
#pragma pack(1)
Во-первых, размеры целочисленных типов могут варьироваться в зависимости от архитектуры. Здесь есть хороший стол: http://en.cppreference.com/w/cpp/language/types
Во-вторых, указатели имеют разные размеры в зависимости от архитектуры. 32-битные машины имеют 32-битные указатели, а 64-битные машины имеют 64-битные указатели. Если вас интересуют более старые архитектуры, 8-битные машины имели 16-битные указатели, а 16-битные машины имели 32-битные указатели, хотя на 8086 они работали странно.
Наконец, что происходит в вашей структуре, вероятно, выравнивание. По соображениям эффективности переменные выровнены по границам слова, а размер слова может отличаться в разных архитектурах. Смотрите больше информации здесь: http://en.cppreference.com/w/cpp/language/object#Alignment