Упакованные битовые поля в c-структурах - GCC
Я работаю с structs в c на linux.
Я начал использовать битовые поля и "упакованный" атрибут, и я наткнулся на странное поведение:
struct t1
{
int a:12;
int b:32;
int c:4;
}__attribute__((packed));
struct t2
{
int a:12;
int b;
int c:4;
}__attribute__((packed));
void main()
{
printf("%d\n",sizeof(t1)); //output - 6
printf("%d\n",sizeof(t2)); //output - 7
}
Почему обе структуры, которые являются точно такими же, принимают различное количество байтов?
Ответы
Ответ 1
Ваши структуры не являются "точно такими же". У вашего первого есть три последовательных битовых поля, второе - одно битовое поле, (не бит-поле) int, а затем второе поле бит.
Это важно: последовательные (отличные от нуля) битовые поля объединяются в единую ячейку памяти, тогда как поле бит, за которым следует небитовое поле, представляет собой различные ячейки памяти.
В вашей первой структуре есть одна ячейка памяти, вторая - три. Вы можете взять адрес члена b
во второй структуре, а не в первой. Доступ к элементу b
не выполняется с доступом к a
или c
во второй структуре, но они выполняются в первую очередь.
Имея небитовое поле (или бит-поле нулевой длины) сразу после того, как член бит-поля "закрывает" его в определенном смысле, последующим будет другое/независимое местоположение/объект памяти. Компилятор не может "упаковать" ваш член b
внутри поля бит, как в первой структуре.
Ответ 2
struct t1 // 6 bytes
{
int a:12; // 0:11
int b:32; // 12:43
int c:4; // 44:47
}__attribute__((packed));
struct t1 // 7 bytes
{
int a:12; // 0:11
int b; // 16:47
int c:4; // 48:51
}__attribute__((packed));
Регулярный int b
должен быть выровнен по границе байта. Таким образом, перед ним есть прокладка. Если вы положите c
рядом с a
, это дополнение больше не понадобится. Вероятно, вы должны это сделать, поскольку доступ к целым числам, не равным байтам, таким как int b:32
, выполняется медленно.