MSVC по умолчанию выравнивание памяти 8 - PullRequest
5 голосов
/ 07 декабря 2011

Согласно MSDN , команда /Zp по умолчанию равна 8, что означает использование 64-битных границ выравнивания.Я всегда предполагал, что для 32-битных приложений компилятор MSVC будет использовать 32-битные границы.Например:

struct Test
{
   char foo;
   int bar;
};

Компилятор дополнит его следующим образом:

struct Test
{
   char foo;
   char padding[3];
   int bar;
};

Итак, поскольку /Zp8 используется по умолчанию, означает ли это, что мой отступ становится 7 + 4 байтаиспользуя тот же пример выше:

struct Test
{
   char foo;
   char padding1[7];
   int bar;
   char padding2[4];
}; // Structure has 16 bytes, ending on an 8-byte boundary

Это немного нелепо, не так ли?Я неправильно понимаю?Почему используется такая большая прокладка, это кажется пустой тратой пространства.Большинство типов в 32-битной системе даже не собираются использовать 64-битные, поэтому большинство переменных будет иметь заполнение (вероятно, более 80%).

Ответы [ 2 ]

9 голосов
/ 07 декабря 2011

Это не так, как это работает. Члены выровнены по кратному их размеру. Символьный до 1 байта, короткий до 2, int до 4, двойной до 8. Структура дополняется в конце, чтобы гарантировать правильное выравнивание элементов при использовании структуры в массиве.

Упаковка из 8 означает, что она перестает пытаться выровнять элементы, которые больше 8. Что является практическим пределом, распределитель памяти не возвращает адреса, выровненные лучше, чем 8. И двойной является жестоко дорогим, если не выровнен правильно и в конечном итоге перекидывает строку кэша. Но в противном случае головная боль, если вы пишете SIMD-код, требует выравнивания 16 байт.

3 голосов
/ 07 декабря 2011

Это не означает, что каждый элемент выровнен по 8-байтовой границе.Прочитайте немного более внимательно:

the smaller member type or n-byte boundaries

Ключом здесь является первая часть - «меньший тип элемента».Это означает, что элементы с меньшим выравниванием могут быть эффективно выровнены меньше.

struct x {
    char c;
    int y;
};
std::cout << sizeof(x);
std::cout << "offsetof(x, c) = " << offsetof(x, c) << '\n';
std::cout << "offsetof(x, c) = " << offsetof(x, y) << '\n';

Это дает 8, 0, 4 - это означает, что на самом деле int дополняется только выравниванием 4 байта.*

...