Как размер структуры может быть не кратным 4? - PullRequest
1 голос
/ 09 апреля 2019

Я новичок в структурах и изучал, как найти размер структур.Я знаю, как вводится отступ, чтобы правильно выровнять память.Из того, что я понял, выравнивание сделано так, чтобы размер в памяти оказался кратным 4. Я попробовал следующий фрагмент кода на GCC.

struct books{
  short int number;
  char name[3];
}book;
printf("%lu",sizeof(book));

Сначала я думал, чтокороткий int должен занимать 2 байта, за которым следует массив символов, начиная с третьей ячейки памяти с самого начала.Массив символов тогда будет нуждаться в заполнении 3 байтами, что даст размер 8. Примерно так: каждое слово представляет байт в памяти.

короткий короткий символ char

заполнение символаpadding padding

Однако при запуске он дает размер 6, что меня смущает.

Любая помощь будет оценена, спасибо!

Ответы [ 3 ]

4 голосов
/ 09 апреля 2019

Как правило, заполнение вставляется для обеспечения выравниваемого доступа к внутренним элементам структуры , а не для того, чтобы вся структура была размером в несколько слов.Выравнивание - это проблема реализации компилятора, а не требование стандарта C.

Итак, элементы char длиной 3 байта не нуждаются в выравнивании, поскольку они являются байтовыми элементами.

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

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

РЕДАКТИРОВАТЬ: .Как упоминает @Euguen Sh, даже если вы обнаружите схему заполнения, которую компилятор использует для структуры, компилятор может изменить ее в другой версии компилятора.

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

Оператор sizeof () используется для того, чтобы увидеть, сколько памяти используется, и узнать, сколько будет добавлено в ptr в структуру, если этот указатель будет увеличен на 1 (ptr ++).

РЕДАКТИРОВАТЬ 2, Упаковка : Структуры могут быть упакованы для предотвращения заполнения, используя атрибут __packed__.При проектировании конструкции целесообразно использовать элементы, которые естественным образом упаковываются.Это особенно важно при отправке данных по линии связи.Тщательно продуманная конструкция исключает необходимость прокладки в середине строения.Плохо спроектированная структура, которая затем компилируется с атрибутом __packed__, может иметь внутренние элементы, которые не выровнены естественным образом.Можно было бы сделать это, чтобы гарантировать, что структура будет передавать по проводу, как это было первоначально разработано.Этот тип усилий уменьшился с введением JSON для передачи данных по проводам.

2 голосов
/ 09 апреля 2019
#include <stdalign.h>
#include <assert.h>

Размер структуры всегда делится на максимальное выравнивание элементов (которое должно быть степенью двойки).Если у вас есть структура с char и short, выравнивание равно 2, потому что выравнивание short равно двум, если у вас есть структура, только из char s оно имеет выравнивание 1.

Существует несколько способов управления выравниванием:

alignas(4) char[4]; // this can hold 32-bit ints

Это нестандартный вариант, но он доступен в большинстве компиляторов (GCC, Clang, ...):

struct A {
    char a;
    short b;
};

struct __attribute__((packed)) B {
    char a;
    short b;
};

static_assert(sizeof(struct A) == 4);
static_assert(alignof(struct A) == 2);

static_assert(sizeof(struct B) == 3);
static_assert(alignof(struct B) == 1);
0 голосов
/ 09 апреля 2019

Обычно компиляторы следуют ABI целевой архитектуры. Он определяет выравнивания структур и примитивных типов данных. И это влияет на необходимые отступы и размеры конструкций. Поскольку выравнивание кратно 4 во многих архитектурах, размер структур слишком велик.

Компиляторы могут предлагать некоторые атрибуты / опции для более или менее прямого изменения выравнивания.

Например, предложения gcc и clang: __attribute__ ((packed))

...