У меня есть фон C#. Я - в значительной степени новичок на низкоуровневый язык как C.
В C#, struct
память размечается компилятором по умолчанию. Компилятор может переупорядочить поля данных или заполнить дополнительные биты между полями неявно. Так, я должен был указать некоторый специальный атрибут для переопределения этого поведения для точного расположения.
AFAIK, C не переупорядочивает или выравнивает расположение памяти a struct
по умолчанию. Однако я слышал, что существует немного исключения, которое очень трудно найти.
Что такое поведение расположения памяти C? Каков должен быть re-ordered/aligned и нет?
В C компилятору разрешено диктовать некоторое выравнивание для каждого примитивного типа. Обычно выравнивание - это размер шрифта. Но это полностью зависит от реализации.
Добавлены байты заполнения, чтобы каждый объект был правильно выровнен. Повторный заказ не допускается.
Возможно, каждый удаленно современный компилятор реализует #pragma pack
, который позволяет управлять заполнением и оставляет его программисту, чтобы он соответствовал ABI. (Это, однако, строго нестандартно.)
Из C99 §6.7.2.1:
12 Каждый член небитового поля структуры или объекта объединения выравнивается в Определяемый реализацией способ , соответствующий его типу.
13 В объекте структуры небитовые поля элементы и блоки, в которых находятся битовые поля, имеют адреса, которые увеличиваются в порядок, в котором они объявлены. Указатель на объект структуры , преобразованный соответствующим образом, указывает на его начальный член (или, если этот член является битовым полем, то на единицу в {{1} }, в котором он находится), и наоборот. Внутри объекта структуры может быть безымянное заполнение, но не в его начале .
Это зависит от реализации, но на практике правило (при отсутствии #pragma pack
или подобного) следующее:
sizeof (T)
байтов. Итак, учитывая следующую структуру:
struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
ch1
находится по смещению 0 s
со смещением 2 ch2
находится по смещению 4, сразу после того, как s ll
со смещением 8 i
находится со смещением 16, сразу после ll Итак sizeof (ST)
равен 24.
Его можно уменьшить до 16 байт, переставив элементы, чтобы избежать заполнения:
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
Вы можете начать с чтения статьи в Википедии о выравнивании структуры данных , чтобы лучше понять выравнивание данных.
Выравнивание данных означает размещение данных со смещением памяти, равным некоторому кратному размеру слова, что увеличивает производительность системы из-за того, как процессор обрабатывает память. Чтобы выровнять данные, может потребоваться вставить несколько бессмысленных байтов между концом последней структуры данных и началом следующей, что является заполнением структуры данных.
Из 6.54.8 Прагмы упаковки структуры документации GCC:
Для совместимости с компиляторами Microsoft Windows GCC поддерживает набор директив #pragma, которые изменяют максимум выравнивание элементов структур (кроме битовых полей нулевой ширины), объединений и классов , определенных впоследствии. Приведенное ниже значение n всегда должно быть малой степенью двойки и определяет новое выравнивание в байтах.
#pragma pack (n)
просто устанавливает новое выравнивание.#pragma pack ()
устанавливает выравнивание на то, которое было в эффекте при запуске компиляции (см. также параметр командной строки -fpack-struct [ =] см. Параметры генерации кода).#pragma pack (push [, n])
помещает текущую настройку выравнивания во внутренний стек , а затем (необязательно) устанавливает новое выравнивание.#pragma pack (pop)
восстанавливает настройку выравнивания до значения, сохраненного в верхней части внутреннего стека (а удаляет эту запись в стеке). Обратите внимание, что#pragma pack ([n])
не влияет на этот внутренний стек; таким образом, возможно иметь#pragma pack (push)
, за которым следует несколько экземпляров#pragma pack (n)
и завершено одним#pragma pack (pop)
.Некоторые цели, например i386 и powerpc, поддерживают ms_struct
#pragma
, которая представляет структуру в соответствии с документированным__ attribute__ ((ms_struct))
.
#pragma ms_struct on
включает макет для объявленных структур.#pragma ms_struct off
отключает макет для объявленных структур.#pragma ms_struct reset
возвращает макет по умолчанию.