Я определил эту структуру:
typedef struct
{
char A:3;
char B:3;
char C:3;
char D:3;
char E:3;
} col;
sizeof(col)
Дать мне выход 3, но она не должна быть 2? Если я прокомментирую только один элемент, то sizeof
будет 2. Я не понимаю, почему: пять элементов по 3 бита равны 15 битам, а это меньше 2 байтов.
Есть ли «внутренний размер» в определении такой структуры? Мне просто нужно пояснение, потому что, исходя из моего представления о языке, я ожидал, что размер будет 2 байта, а не 3.
signed char
илиunsigned char
, вы не можете сказать, не просматривая документацию, будет ли компилятор рассматривать `` простой ''char
в битовом поле как подписанный или неподписанный, и решение может (теоретически) отличаться от решения о том, будет ли 'plain'char
является знаковым или беззнаковым при использовании вне битового поля._Bool
,signed int
,unsigned int
или какими - либо других реализацией определенных типов. Использованиеchar
поэтому попадает в категорию «другие реализации определенных типа».Ответы:
Поскольку вы используете
char
в качестве базового типа для своих полей, компилятор пытается сгруппировать биты по байтам, и, поскольку он не может помещать более восьми бит в каждый байт, он может хранить только два поля на байт.Общая сумма битов, используемых вашей структурой, равна 15, поэтому идеальным размером для размещения такого количества данных будет файл
short
.#include <stdio.h> typedef struct { char A:3; char B:3; char C:3; char D:3; char E:3; } col; typedef struct { short A:3; short B:3; short C:3; short D:3; short E:3; } col2; int main(){ printf("size of col: %lu\n", sizeof(col)); printf("size of col2: %lu\n", sizeof(col2)); }
Приведенный выше код (для 64-битной платформы, такой как моя) действительно даст результат
2
для второй структуры. Для всего, что больше ashort
, структура будет заполнять не более одного элемента используемого типа, поэтому - для той же платформы - структура будет иметь размер четыре дляint
, восемь дляlong
и т. Д.источник
char
иshort
?char
без подписи…Поскольку у вас не может быть битового поля пакета, которое охватывает минимальную границу выравнивания (которая составляет 1 байт), поэтому они, вероятно, будут упакованы как
byte 1 A : 3 B : 3 padding : 2 byte 2 C : 3 D : 3 padding : 2 byte 3 E : 3 padding : 5
(порядок полей / отступов внутри одного байта не является преднамеренным, он просто дает вам представление, поскольку компилятор может установить их так, как он предпочитает)
источник
Первые два битовых поля помещаются в одно
char
. Третий в это не влезетchar
и ему нужен новый. 3 + 3 + 3 = 9, что не вписывается в 8-битный символ.Таким образом, первая пара принимает a
char
, вторая пара принимает achar
, а последнее битовое поле получает третьеchar
.источник
Большинство компиляторов позволяют управлять заполнением, например, с помощью
#pragma
s . Вот пример с GCC 4.8.1:#include <stdio.h> typedef struct { char A:3; char B:3; char C:3; char D:3; char E:3; } col; #pragma pack(push, 1) typedef struct { char A:3; char B:3; char C:3; char D:3; char E:3; } col2; #pragma pack(pop) int main(){ printf("size of col: %lu\n", sizeof(col)); // 3 printf("size of col2: %lu\n", sizeof(col2)); // 2 }
Обратите внимание, что поведение компилятора по умолчанию существует не просто так и, вероятно, даст вам лучшую производительность.
источник
Несмотря на то, что стандарт ANSI C слишком мало определяет, как упаковываются битовые поля, чтобы предложить какое-либо существенное преимущество перед «компиляторам разрешено упаковывать битовые поля, как они считают нужным», тем не менее во многих случаях он запрещает компиляторам упаковывать вещи наиболее эффективным способом.
В частности, если структура содержит битовые поля, компилятор должен сохранить ее как структуру, которая содержит одно или несколько анонимных полей некоторого «нормального» типа хранения, а затем логически разделить каждое такое поле на составляющие его части битового поля. Таким образом, учитывая:
unsigned char foo1: 3; unsigned char foo2: 3; unsigned char foo3: 3; unsigned char foo4: 3; unsigned char foo5: 3; unsigned char foo6: 3; unsigned char foo7: 3;
Если
unsigned char
это 8 бит, компилятор должен будет выделить четыре поля этого типа и назначить два битовых поля всем, кроме одного (которое будет в отдельномchar
поле). Если бы всеchar
объявления были заменены наshort
, то было бы два поля типаshort
, одно из которых могло бы содержать пять битовых полей, а другое - оставшиеся два.На процессоре без ограничений по выравниванию данные могут быть размещены более эффективно, используя
unsigned short
для первых пяти полей иunsigned char
последних двух, сохраняя семь трехбитовых полей в трех байтах. Хотя должна быть возможность хранить восемь трехбитных полей в трех байтах, компилятор мог разрешить это только при наличии трехбайтового числового типа, который можно было бы использовать как тип «внешнего поля».Лично я считаю, что битовые поля в основном бесполезны. Если код должен работать с двоично упакованными данными, он должен явно определить места хранения фактических типов, а затем использовать макросы или другие подобные средства для доступа к их битам. Было бы полезно, если бы C поддерживал такой синтаксис, как:
unsigned short f1; unsigned char f2; union foo1 = f1:0.3; union foo2 = f1:3.3; union foo3 = f1:6.3; union foo4 = f1:9.3; union foo5 = f1:12.3; union foo6 = f2:0.3; union foo7 = f2:3.3;
Такой синтаксис, если он разрешен, позволил бы коду использовать битовые поля переносимым образом, без учета размеров слов или порядка байтов (foo0 будет в трех младших битах f1, но они могут храниться в нижний или верхний адрес). Однако при отсутствии такой функции макросы, вероятно, являются единственным переносимым способом работы с такими вещами.
источник