Как sizeof вычисляет размер структур

Я знаю, что char и int вычисляются как 8 байт на 32-битных архитектурах из-за выравнивания, но недавно я столкнулся с ситуацией, когда структура с 3 шортами была сообщена как 6 байт оператором sizeof. Код выглядит следующим образом:

#include <iostream>
using namespace std ;

struct IntAndChar
{
    int a ;
    unsigned char b ;
};


struct ThreeShorts
{
    unsigned short a ;
    unsigned short b ;
    unsigned short c ;
};


int main()
{
    cout<<sizeof(IntAndChar)<<endl; // outputs '8'
    cout<<sizeof(ThreeShorts)<<endl; // outputs '6', I expected this to be '8'
    return 0 ;
}

компилятор: g++ (Debian 4.3.2-1.1) 4.3.2. Это действительно озадачивает меня, почему выравнивание не выполняется для структуры, содержащей 3 шорты?

6 ответов


потому что int составляет 4 байта и должен быть выровнен по границе 4 байта. Это означает, что любой struct содержащий int также должен быть выровнен по крайней мере на 4 байта.

С другой стороны, short составляет 2 байта и требует выравнивания только до границы в 2 байта. Если a struct С shorts не содержит ничего, что требует большего выравнивания,struct также будет выровнен по 2-байтам.


Это действительно озадачивает меня, почему выравнивание не применяется для t

какое выравнивание вы хотите, чтобы он имел ?

шорты могут быть выровнены по 2-байтовым границам без каких-либо негативных последствий(при условии, что здесь используются общие компиляторы x86..). Поэтому, если вы создадите массив struct ThreeeShorts, эта структура, имеющая размер 6, прекрасна, так как любые элементы в таком массиве будут начинаться с 2-байтовой границы.

код struct IntAndChar содержит int, ints хочет выравнивание 4 байтов, поэтому, если вы создадите массив struct IntAndChar размер должен быть 8 для следующего элемента, который будет выровнен по границе 4 байта.

если бы мы не рассматривали массивы, это не имело бы большого значения, если struct IntAndChar были длиной 5 байт, компилятор просто выделил бы его, начиная с 4-байтовой границы, когда вы создаете один стек или используете его как составной элемент в другой структуре.

вы всегда можете получить количество элементов в массиве, выполнив sizeof(arrayofT)/sizeof (T) и элементы массива гарантированно хранятся смежно, так что n-й элемент может быть восстановлен путем шага N*sizeof(arrayelementtype) байтов с самого начала, и это основная причина, по которой вы увидите структуры, дополняемые в конце.


Я не знаю, откуда вы взяли идею о char или int рассчитывается как "8 байт". Нет, каждый тип рассчитывается в соответствии с его размером:char как 1, int как 4 на 32-битной платформе (не 8, а 4). Требований выравнивания для каждого вида обычно совпадает с его размером (хотя это не обязательно).

по этой причине, когда структура содержит члены то же самое тип, общий размер этой структуры, как правило, точная сумма размеров его членов: структура 3 chars будет иметь размер 3, а структура два ints будет иметь размер 8.

видимо типа short на вашей платформе есть размер 2, поэтому, как ожидается, структура из 3 шорт имеет размер 6, что именно то, что вы наблюдаете.

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

например, структура, которая выглядит как следует

struct S {
  char c;
  int i;
};

, скорее всего, займет 8 байт на вашей платформе из-за необходимости 3 байта заполнения после char - члены. Обратите внимание, char считается как 1, int как 4 и дополнительные 3 байта заполнения между ними делают его 8.

Обратите также внимание, что это может легко ввести зависимость конечного размера структуры от порядка, в котором объявляются члены. Например, эта структура

struct S1 {
  char c1;
  int i;
  char c2;
};

на вашей платформе, вероятно, размер 12, при этом один

struct S2 {
  int i;
  char c1;
  char c2;
};

займет всего 8 байт. Этот последний пример призван проиллюстрировать, что конечный размер структуры не может быть выражен в терминах того, сколько байтов каждый член "считает". Отношения между членами также важны.


это полностью зависит от реализации, но, предположительно, если ваша система может получить доступ к любой из трех shorts в структуре, не беспокоясь о выравнивании, он может получить доступ к любому short, и, следовательно, любой член данных, в массиве ThreeShorts не заботясь о выравнивании. Поэтому нет необходимости более строго выравнивать структуры.

на IntAndChar, например, int предположительно имеет размер 4 и реализации is обеспокоенный его выравниванием. Чтобы убедиться, что каждый int член в массиве IntAndChar правильно выровнен, структура должна быть дополнена.

на sizeof массив T[n] точно определяется как sizeof(T) * n.


эта ссылка должна помочь: http://en.wikipedia.org/wiki/Data_structure_alignment

на ThreeShorts все члены выровнены по двум байтам.


Да, у меня была та же проблема. У меня есть следующая структура

struct Node{
    short digit;
    Node* next;
};
    cout<<":"<<sizeof(Node)<<":"<<sizeof(short)<<":"<<sizeof(Node*)<<endl;

Это дает мне ::8:2:4 ?? почему общая сумма для структуры = 8, но отдельные элементы не суммируются?? Это происходит из-за выравнивания памяти, память дополняется дополнительными 2 байтами для выравнивания. Спасибо