Здесь sizeof
прекрасно демонстрирует, что происходит под капотом:
#include <iostream>
#include <climits>
struct bc_1 {
int a : 1;
int b : 1;
};
struct bc_2 {
int a : 31;
int b : 1;
};
struct bc_3 {
int a : 32;
int b : 1;
};
struct bc_4 {
int a : 31;
int b : 2;
};
struct bc_5 {
int a : 32;
int b : 32;
};
struct bc_6 {
int a : 40;
int b : 32;
};
struct bc_7 {
int a : 63;
int b : 1;
};
int main(int argc, char * argv[]) {
std::cout << "CHAR_BIT = " << CHAR_BIT;
std::cout << " => sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "1, 1: " << sizeof(struct bc_1) << std::endl;
std::cout << "31, 1: " << sizeof(struct bc_2) << std::endl;
std::cout << "32, 1: " << sizeof(struct bc_3) << std::endl;
std::cout << "31, 2: " << sizeof(struct bc_4) << std::endl;
std::cout << "32, 32: " << sizeof(struct bc_5) << std::endl;
std::cout << "40, 32: " << sizeof(struct bc_6) << std::endl;
std::cout << "63, 1: " << sizeof(struct bc_7) << std::endl;
}
Дальнейшие действия зависят от вашего компилятора и операционной системы, а также от вашего оборудования В macOS с gcc-7 (с CHAR_BIT
= 8 32-битный int
(т.е. половина 64-битного long
) имеет sizeof(int)
= 4), это вывод, который я вижу:
CHAR_BIT = 8 => sizeof(int) = 4
1, 1: 4
31, 1: 4
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 12
63, 1: 8
Это говорит нам о нескольких вещах: если оба поля типа int
помещаются в один int
(т. Е. 32 бита в приведенном выше примере), компилятор выделяет только одну int
память (bc_1
и bc_2
). Как только один int
больше не может содержать битовые поля, мы добавляем второе (bc_3
и bc_4
). Обратите внимание, что bc_5
на полную мощность.
Интересно, что мы можем «выбрать» больше битов, чем разрешено. Смотри bc_6
. Здесь g ++ - 7 выдает предупреждение:
bitfields.cpp::30:13: warning: width of 'bc_6::a' exceeds its type
int a : 40;
^~
Обратите внимание: clang ++ объясняет это более подробно
bitfields.cpp:30:9: warning: width of bit-field 'a' (40 bits) exceeds the width of its type; value will be truncated to 32 bits [-Wbitfield-width]
int a : 40;
^
Однако кажется, что под капотом компилятор выделяет еще одну int
память. Или, по крайней мере, он определяет правильный размер. Я предполагаю, что компилятор предупреждает нас, чтобы мы не обращались к этой памяти как int a = bc_6::a
(я бы поспорил, что int a
будет тогда иметь только первые 32 бита поля bc_6::a
...). Это подтверждается bc_7
, общий размер которого равен двум int
с, но первое поле охватывает большинство из них.
Наконец, замена int
на long
в приведенном выше примере ведет себя как ожидалось:
CHAR_BIT = 8 => sizeof(long) = 8
1, 1: 8
31, 1: 8
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 16
63, 1: 8