Проблема выравнивания классов

Я тестировал выравнивание классов и обнаружил странное поведение. Я протестировал его с настройкой компилятора VS2012 4 и 8 выравнивания байтов, но в каждом случае вывод одинаковый.

class Alignemnt{
public:
    Alignemnt():a(){}
    int a;
};

class Alignemnt_1{
public:
    int a;
    char array[2];
};

class Alignemnt_2{
public:
    int a;
    char array[2];
    int x;
};

std::cout <<  "Sizeof(Alignemnt)   :" <<sizeof(Alignemnt) << std::endl;
std::cout <<  "Sizeof(Alignemnt_1) :" <<sizeof(Alignemnt_1) << std::endl;
std::cout <<  "Sizeof(Alignemnt_2) :" <<sizeof(Alignemnt_2) << std::endl;

Каждый раз вывод:

Sizeof(Alignemnt)   : 4

Sizeof(Alignemnt_1) : 8

Sizeof(Alignemnt_2) : 12

Я думаю, размер Alignemnt_2 должен быть 16 байт.


person CrazyC    schedule 29.01.2015    source источник
comment
Итак, какой у вас вопрос? Мне кажется, что с компилятором все в порядке?   -  person gha.st    schedule 29.01.2015
comment
Я думаю, размер Alignemnt_2 должен быть 16 байт.   -  person CrazyC    schedule 29.01.2015
comment
int обычно выравнивается по 4 байтам. char[2] — это всего лишь 2-байтовый объект. Вы получаете размер 12 байт, потому что первый int занимает 4 байта, второй объект занимает 2 байта, а третий должен быть выровнен по 4 байтам.   -  person Charlie    schedule 29.01.2015
comment
@TonyD Размер кратен выравниванию, поэтому выравнивание влияет на размер. И это даже не говоря о том, что выравнивание member делает с размером содержащего объекта.   -  person gha.st    schedule 29.01.2015
comment
Может быть, ему стоит попытаться составить больше тестов! Немного почитав, я подумал, может компилятор Visual Studio особым образом оптимизирует хранение данных?   -  person Cinch    schedule 29.01.2015
comment
Меня поражает, что я не знаю, какие настройки вы используете или как они работают между объектами и членами структуры. Если элементы структуры должны быть выровнены по 8 байтам, тогда № 2 должен быть 24 байта (или 20 байт), но если выравнивание находится на уровне выделения объекта/памяти, то оно не изменяет размер вашего структура вообще.   -  person Charlie    schedule 29.01.2015
comment
Немного оффтопа: вы можете использовать struct вместо class по причинам тестирования, чтобы сэкономить ваше время и не печатать ключевое слово public   -  person borisbn    schedule 29.01.2015


Ответы (3)


Я предполагаю, что вы имеете в виду переключатель /Zp, который позволяет вам управлять максимальное выравнивание элементов структуры:

Когда вы указываете эту опцию, каждый член структуры после первого сохраняется либо в размере типа члена, либо в n-байтовых границах (где n равно 1, 2, 4, 8 или 16), в зависимости от того, что меньше.

Поскольку вы не используете член структуры с выравниванием более 4 байтов (sizeof(int) и alignof(int) оба равны 4), все настройки 4 байта и выше приведут к точно такому же поведению.

Если вы хотите указать точное выравнивание члена структуры, рассмотрите возможность использования стандартного C++ alignas, который позволяет вам указать точное выравнивание, которое должен иметь член (VS 2012 должен поддерживать его iirc).

Посмотрите результат использования alignas.

person gha.st    schedule 29.01.2015

Выравнивание не должно изменять размер вашего объекта, только начальный адрес объектов. Например, объект с выравниванием по 8 байтам может иметь адрес 0x100000 или 0x100008, или любой адрес, оканчивающийся на 0 или 8, если он записан в шестнадцатеричном формате, но не на 0x100004.

person Charlie    schedule 29.01.2015
comment
Я не согласен с этим. выравнивание связано с отступами, которые изменяют размер объекта. - person CrazyC; 29.01.2015
comment
Кроме того, размер объекта будет кратен его выравниванию. - person gha.st; 29.01.2015
comment
Да. @gha..st. Выравнивание всегда дает размер объекта, кратный настройке. Здесь я сделал 8 байт, поэтому вместо 12 должно быть 16. - person CrazyC; 29.01.2015
comment
Размер не зависит от выравнивания. Выравнивание влияет на эффективность упаковки, но не на количество байтов, необходимых для хранения объекта. Например, если я упаковываю объект, который должен быть выровнен по 8 байтам рядом с чем-то, что не имеет значения, нет необходимости в дополнении. - person Charlie; 29.01.2015
comment
@Charlie Если вы не говорите о сверхвыровненном типе, взгляните на этот пример, который делает именно это: упакуйте Объект с выравниванием и размером 8 байт рядом с объектом с выравниванием и размером 1 байт. Размер изменяется с 9 байт на 16 байт при изменении выравнивания первого члена. - person gha.st; 29.01.2015
comment
@gha.st Я думал что-то о том, применяется ли выравнивание на уровне структуры или (т.е. структура может быть выровнена по 8 байтам, но выравнивание не следует членам) по сравнению с выравниванием элементов - выравнивание применяется к уровень структуры по сравнению с alignas применяется к каждому элементу. - person Charlie; 29.01.2015

No.

Выравнивание 2 в порядке.

У вас есть 2 символа рядом друг с другом, это означает, что вы используете 2 из 4 байтов. Упаковка выровняет его до 4 байтов, и тогда вы получите 4 + 4 +4 .

Если вы хотите закончить до 16, вы можете попробовать следующее объявление:

 {
      char a;
      int b;
      char c;
      int d;
 }
person MichaelCMS    schedule 29.01.2015
comment
@CrazyC Есть ли причина для отрицательного голоса? Есть ли что-то, что я сказал не так? или вам просто нравится минусовать ради минусовки? - person MichaelCMS; 29.01.2015
comment
@CrazyC ах, извините. Я думал, ты проголосовал против. Тем не менее, я все же хотел бы знать, почему downvoter проголосовал против ... - person MichaelCMS; 29.01.2015