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

Я знаю, что char и int вычисляются как 8 байтов на 32-битных архитектурах из-за выравнивания, но я недавно столкнулся с ситуацией, когда структура с тремя шортами была зарегистрирована как 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 шорта?

Ответы

Ответ 1

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

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

Ответ 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) байт с самого начала, и что основная причина, по которой вы увидите, что в конце создаются структуры.

Ответ 3

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

По этой причине, когда структура содержит члены того же типа, общий размер этой структуры обычно будет точной суммой размеров его членов: структура 3 char будет иметь размер 3 и структура двух int будет иметь размер 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 байтов. Этот последний пример предназначен для иллюстрации того, что конечный размер структуры не может быть выражен в терминах количества байтов, для каждого члена которого "подсчитывается". Также важны отношения между членами.

Ответ 4

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

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

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

Ответ 6

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

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

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