Размер структуры, содержащей битовые поля
Возможный дубликат:
Почему sizeof для структуры не равен сумме sizeof каждого члена?
Я пытался понять концепцию битовых полей. Но я не могу найти, почему размер следующей структуры в CASE III составляет 8 байтов.
СЛУЧАЙ I:
struct B
{
unsigned char c; // +8 bits
} b;
SizeOf(б); // Вывод: 1 (потому что беззнаковый символ занимает 1 байт в моей системе)
СЛУЧАЙ II:
struct B
{
unsigned b: 1;
} b;
sizeof(b); // Output: 4 (because unsigned takes 4 bytes on my system)
СЛУЧАЙ III:
struct B
{
unsigned char c; // +8 bits
unsigned b: 1; // +1 bit
} b;
sizeof(b); // Output: 8
Я не понимаю, почему вывод для случая III получается как 8. Я ожидал 1 (символ) + 4(без знака) = 5.
6 ответов
Вы можете проверить макет структуры с помощью offsetof
, но это будет что-то вроде:
struct B
{
unsigned char c; // +8 bits
unsigned char pad[3]; //padding
unsigned int bint; //your b:1 will be the first byte of this one
} b;
Теперь очевидно, что (в 32-битной арке) sizeof(b)
будет 8
не так ли?
Вопрос в том, почему 3 байта заполнения, а не более или менее?
Ответ заключается в том, что смещение поля в структуре имеет те же требования к выравниванию, что и тип самого поля. В вашей архитектуре целые числа выровнены по 4 байта, поэтому offsetof(b, bint)
должно быть кратным 4. Это не может быть 0, потому что есть c
раньше, так будет 4. Если поле bint
начинается со смещения 4 и имеет длину 4 байта, затем размер структуры равен 8.
Другой способ взглянуть на это состоит в том, что требование выравнивания структуры является самым большим из всех ее полей, так что это B
будет выровнен по 4 байта (так как это ваше битовое поле). Но размер типа должен быть кратным выравниванию, 4 недостаточно, поэтому будет 8.
Я думаю, что вы видите эффект выравнивания здесь.
Многие архитектуры требуют, чтобы целые числа сохранялись по адресам в памяти, кратным размеру слова.
Вот почему символ в вашей третьей структуре дополняется еще тремя байтами, так что следующее целое число без знака начинается с адреса, кратного размеру слова.
Char по определению является байтом. В 32-битной системе значения int составляют 4 байта. И структура дополняется дополнительными 4.
См. http://en.wikipedia.org/wiki/Data_structure_alignment для некоторых объяснений заполнения
Выравнивание и общий размер структуры зависят от платформы и компилятора. Вы не можете не ожидать простых и предсказуемых ответов здесь. У компилятора всегда может быть какая-то особая идея. Например:
struct B
{
unsigned b0: 1; // +1 bit
unsigned char c; // +8 bits
unsigned b1: 1; // +1 bit
};
Компилятор может объединять поля b0 и b1 в одно целое число и не может. Это зависит от компилятора. У некоторых компиляторов есть ключи командной строки, которые управляют этим, у некоторых нет. Другой пример:
struct B
{
unsigned short c, d, e;
};
Компилятор должен упаковать / не упаковать поля этой структуры (при условии 32-битной платформы). Структура структуры может отличаться между сборками DEBUG и RELEASE.
Я бы рекомендовал использовать только следующий шаблон:
struct B
{
unsigned b0: 1;
unsigned b1: 7;
unsigned b2: 2;
};
Если у вас есть последовательность битовых полей, которые имеют один и тот же тип, компилятор поместит их в один тип int. В противном случае могут возникнуть различные аспекты. Также учтите, что в большом проекте вы пишете кусок кода, а кто-то другой будет писать и перезаписывать make-файл; переместите свой код из одной библиотеки в другую. На этом этапе флаги компилятора будут установлены и изменены. 99% вероятности, что эти люди не будут знать о требованиях к выравниванию вашей структуры. Они даже не откроют ваш файл никогда.
Чтобы сохранить доступ к памяти выровненным, компилятор добавляет заполнение, если вы упакуете структуру, он не добавит дополнение.
Я еще раз взглянул на это, и вот что я нашел.
- Из книги C: "Почти все в полях зависит от реализации".
- На моей машине:
struct B { unsigned c: 8; unsigned b: 1; }b; printf("%lu\n", sizeof(b));
печать 4, которая является короткой;
Вы смешивали битовые поля с обычными элементами структуры.
Кстати, битовые поля определены как: "набор смежных битов в блоке хранения, заданном реализацией sindle". Итак, я даже не уверен, что ':8' делает то, что вы хотите. Казалось бы, это не в духе битовых полей (поскольку это уже не бит)