размер структуры, содержащей битовые поля

Возможный дубликат:
Почему sizeof для структуры не равен сумме sizeof каждого члена?

Я пытался понять концепцию битовых полей. Но я не могу понять, почему размер следующей структуры в CASE III составляет 8 байтов.

СЛУЧАЙ I:

struct B    
{
    unsigned char c;  // +8 bits
} b;

sizeof (b); // Вывод: 1 (поскольку беззнаковый char занимает в моей системе 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 (char) + 4 (unsigned) = 5.


person user1367292    schedule 06.10.2012    source источник
comment
вы видите заполнение структуры. выполните поиск по этим терминам на этом сайте, и вы найдете много информации   -  person pb2q    schedule 06.10.2012
comment
unsigned char занимает один байт в каждой системе.   -  person Carl Norum    schedule 06.10.2012
comment
@CarlNorum: Верно, но это не значит, что struct с одним char (например, в случае I) тоже занимает один байт. Другой компилятор мог бы добавить к структуре три байта заполнения.   -  person MSalters    schedule 06.10.2012
comment
@MSalters, да, безусловно, может. Я не уверен, что понимаю, к чему вы клоните?   -  person Carl Norum    schedule 06.10.2012


Ответы (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.

person rodrigo    schedule 06.10.2012

Я думаю, вы видите здесь эффект выравнивания.

Многие архитектуры требуют, чтобы целые числа хранились по адресам в памяти, кратным размеру слова.

Вот почему char в вашей третьей структуре дополняется еще тремя байтами, так что следующее целое число без знака начинается с адреса, кратного размеру слова.

person rodion    schedule 06.10.2012

Char по определению является байтом. ints - это 4 байта в 32-битной системе. И структура дополняется дополнительными 4.

См. http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86 для получения дополнительной информации. набивки

person Avi    schedule 06.10.2012
comment
в приведенном выше case3 char составляет 8 бит (пока без проблем). и я предоставил только 1 бит без знака int. Это означает, что оставшийся 31 бит будет дополнен. Но все же размер должен быть --- 8 бит (char) + 1 бит (который я предоставил) + 31 бит (из-за заполнения) == 40 бит или 4 байта. Почему получается 8 байтов? - person user1367292; 06.10.2012
comment
Невозможно просто добавить немного больше в архитектуру. беззнаковое int составляет 4 байта в вашей системе - person Avi; 06.10.2012

Чтобы доступ к памяти был выровнен, компилятор добавляет заполнение, если вы упаковываете структуру, он не будет добавлять заполнение.

person GriffinHeart    schedule 06.10.2012

Я еще раз взглянул на это и вот что нашел.

  1. Из книги C: «Почти все в полях зависит от реализации».
  2. На моей машине:
 struct B {
    unsigned c: 8;
    unsigned b: 1;
}b;
printf("%lu\n", sizeof(b));

выведите 4, что является коротким;

Вы смешивали битовые поля с обычными элементами структуры.

Кстати, битовые поля определяются как: «набор смежных битов в блоке хранения, определяемом реализацией sindle». Итак, я даже не уверен, что «: 8» делает то, что вы хотите. Казалось бы, это не в духе битовых полей (так как это уже не бит)

person Avi    schedule 06.10.2012

Выравнивание и общий размер структуры зависят от платформы и компилятора. Здесь нельзя не ожидать однозначных и предсказуемых ответов. У компилятора всегда может быть какая-то особенная идея. Например:

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-файл; переместите свой код из одной dll в другую. На этом этапе будут установлены и изменены флаги компилятора. Вероятность 99%, что эти люди не будут иметь представления о требованиях к выравниванию вашей структуры. Они даже не откроют ваш файл.

person Kirill Kobelev    schedule 06.10.2012
comment
Компилятор может объединять поля b0 и b1 в одно целое, а может нет - так ли это? Я думаю, что компилятор должен следить за порядком битовых полей. - person ysap; 13.03.2017
comment
Я считаю, что наиболее важным принципом является точное сохранение наблюдаемого поведения. Все остальное может быть не таким точным, может отличаться от компилятора к компилятору, от платформы к платформе и т. Д. Было бы неправильно смотреть на черно-белый мир, где это происходит именно так, а что-то другое - иначе. Многие вещи находятся в серой зоне. - person Kirill Kobelev; 19.03.2017