Соответствующая часть стандарта: C11 / C17 6.7.2.1p11 :
- Реализация может выделить любую адресуемую единицу хранения, достаточно большую для хранения битового поля . Если остается достаточно места, битовое поле, которое следует сразу за другим битовым полем в структуре, должно быть упаковано в смежные биты той же единицы. Если остается недостаточно места, определяется ли битовое поле, которое не умещается, в следующем блоке или перекрывает смежные блоки, определяется реализацией. Порядок распределения битовых полей в блоке (от старшего к младшему или от младшего к старшему) определяется реализацией. Выравнивание адресуемой единицы хранения не указано.
что в связи с C11 / C17 6.7.2.1p5
- A. битовое поле должно иметь тип, который является квалифицированной или неквалифицированной версией _Bool, со знаком int, без знака int или каким-либо другим определяемым реализацией типом . Это определяется реализацией, разрешены ли атомарные типы.
и то, что вы используете char
, означает, что вообще нечего обсуждать - для конкретной реализации проверьте руководства по компилятору. Вот тот, для GCC .
Из 2 отрывков следует, что реализация может свободно использовать абсолютно любых типов, которые она хочет для реализации битовых полей - она может даже использовать int64_t
для обоих этих случаев, имеющих структуру размера 16 байт. Единственное, что должна сделать соответствующая реализация , - это упаковать биты в выбранную адресуемую единицу хранения, если остается достаточно места.
Для GCC на System-V ABI на 386-совместимых (32-разрядных процессорах) , следующие стенды:
Обычные битовые поля (то есть те, которые ни signed
, ни unsigned
) всегда имеют неотрицательные значения. Хотя они могут иметь тип char
, short
, int
, long
(которые могут иметь отрицательные значения),
эти битовые поля имеют тот же диапазон, что и битовые поля одинакового размера
с соответствующим типом unsigned
. Битовые поля подчиняются тем же
Размер и правила выравнивания, как и другие структуры и члены профсоюза, с
следующие дополнения:
- Битовые поля располагаются справа налево (наименее значимым).
Битовое поле должно полностью находиться в единице памяти, соответствующей его объявленному типу. Таким образом, битовое поле никогда не пересекает свою единичную границу.
Битовые поля могут совместно использовать единицу хранения с другими struct
/ union
элементами, включая элементы, которые не являются битовыми полями. Конечно,
struct
Члены занимают разные части хранилища.
Типы безымянных битовых полей не влияют на выравнивание структуры или объединения, хотя смещения элементов отдельных битовых полей подчиняются
ограничения выравнивания.
т.е. в System-V ABI, 386, int f: 1
говорит, что битовое поле f
должно быть в пределах int
. Если остаются все байты пространства, следующие char
в той же структуре будут упакованы внутри этого int
, даже если это не битовое поле.
Используя эти знания, макет для
struct {
int a : 1; // 1 bit - bit 0
int b : 2; // 2 bits - bits 2 down to 1
char c ; // 8 bits - bits 15 down to 8
} reg1;
будет
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|a b b x x x x x|c c c c c c c c|x x x x x x x x|x x x x x x x x|
<------------------------------ int ---------------------------->
и макет для
struct {
char a : 1; // 1 bit - bit 0
char b : 2; // 2 bits - bits 2 down to 1
char c ; // 8 bits - bits 15 down to 8
} reg1;
будет
1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|a b b x x x x x|c c c c c c c c|
<---- char ----><---- char ---->
Так что есть сложные крайние случаи. Сравните 2 определения здесь:
struct x {
short a : 2;
short b : 15;
char c ;
};
struct y {
int a : 2;
int b : 15;
char c ;
};
Поскольку битовое поле не должно пересекать границу устройства, struct x
члены a
и b
должны переходить на разные шорты. Тогда не хватает места для размещения char c
, поэтому он должен прийти после этого. И вся структура должна быть соответствующим образом выровнена для short
, поэтому на i386 будет 6 байтов. Последний, тем не менее, будет упаковывать a
и b
в 17 младших битов int
, и поскольку в int
остается еще один полный адресуемый байт, c
также будет упакован здесь, и, следовательно, sizeof (struct y)
будет 4 .
Наконец, вы должны действительно указать, подписан ли int
или char
или нет - по умолчанию может быть не то, что вы ожидаете! Стандарт оставляет его на усмотрение реализации, и GCC имеет переключатель времени компиляции, чтобы изменить их.