Выравнивание элементов структуры C (ANSI)

простой вопрос … что стандарт говорит о выравнивании элементов структуры?
например с этим:

struct
{
uint8_t a;
uint8_t b;
/* other members */
} test;

Гарантируется, что b находится по смещению 1 от начала структуры?
Спасибо

4

Решение

Стандарт (начиная с C99) ничего не говорит.

Единственные реальные гарантии в том, что (void *)&test == (void *)&aи что a находится по более низкому адресу, чем b, Все остальное зависит от реализации.

7

Другие решения

C11 6.7.2.1 Структура и объединение спецификаторов р14 говорит

Каждый элемент не битового поля структуры или объекта объединения выравнивается в
определяемый реализацией способ, соответствующий его типу.

Это означает, что вы не можете делать какие-либо переносимые предположения о разнице между адресами a а также b,

1

Должно быть возможно использовать offsetof определить смещение членов.

Для C выравнивание определено реализацией, мы можем видеть, что в проекте стандарта C99 6.7.2.1 Спецификаторы структуры и объединения параграф 12(В С11 это будет параграф 14), в котором говорится:

Каждый элемент не битового поля структуры или объекта объединения выровнен способом, определяемым реализацией, соответствующим его типу.

и параграф 13 говорит:

Внутри объекта структуры, элементы не битовых полей и единицы, в которых битовые поля
проживать имеют адреса, которые увеличиваются в том порядке, в котором они объявлены. Указатель на
Объект структуры, соответствующим образом преобразованный, указывает на его начальный элемент (или, если этот элемент является
битовое поле, затем к единице, в которой он находится), и наоборот. Там может быть безымянный
заполнение внутри объекта структуры, но не в его начале.

и для C ++ у нас есть следующие аналогичные цитаты из раздела проекта стандарта 9.2 Члены класса параграф 13 говорит:

Нестатические члены данных (не объединяющего) класса с одинаковым контролем доступа (раздел 11) распределяются так, чтобы более поздние члены имели более высокие адреса в объекте класса. Порядок распределения нестатических элементов данных с различным контролем доступа не определен (раздел 11). Требования выравнивания реализации могут привести к тому, что два смежных элемента не будут выделяться сразу после друг друга;

и параграф 19 говорит:

Указатель на объект структуры стандартной компоновки, соответствующим образом преобразованный с помощью reinterpret_cast, указывает на его
начальный элемент (или, если этот элемент является битовым полем, то к модулю, в котором он находится), и наоборот. [ Заметка:
Следовательно, в объекте структуры стандартной компоновки может быть безымянный отступ, но не в его начале,
по мере необходимости для достижения соответствующего выравнивания. —Конечная записка]

1

случай, который вы используете, на самом деле не является краевым, оба uint_8 достаточно малы, чтобы поместиться в одно и то же слово в памяти, и было бы бесполезно помещать каждый uint_8 в uint_16.

Более критический случай будет что-то вроде:

{
uint8_t a;
uint8_t b;

uint_32 c; // where is C, at &a+2 or &a+4 ?
/* other members */
} test;

и в любом случае это всегда будет зависеть от целевой архитектуры и вашего компилятора …

0

К&Второе издание R (ANSI C) в главе 6.4 (стр. 138) гласит:

Не предполагайте, однако, что размер структуры является суммой размеров ее членов. Из-за требований выравнивания для различных объектов в структуре могут быть безымянные «дыры».

Так что нет, ANSI C не гарантирует, что b по смещению 1.

Вполне вероятно, что компилятор ставит b по смещению sizeof(int) так что он выровнен по размеру машинного слова, с которым легче иметь дело.

Некоторые компиляторы поддерживают вьючные псевдокомментарии так что вы можете заставить, что нет таких «дыр» в struct, но это не портативно.

0

То, что гарантировано C-стандартом, уже упоминалось в других ответах.

Тем не менее, чтобы убедиться, b является по смещению 1 ваш компилятор может предложить варианты «упаковать» структуру, скажет явно добавить нет обивка.

Для GCC это может быть достигнуто #pragma pack().

#pragma pack(1)
struct
{
uint8_t a; /* Guaranteed to be at offset 0. */
uint8_t b; /* Guaranteed to be at offset 1. */
/* other members are guaranteed to start at offset 2. */
} test_packed;
#pragma pack()

struct
{
uint8_t a; /* Guaranteed to by at offset 0. */
uint8_t b; /* NOT guaranteed to be at offset 1. */
/* other members are NOT guaranteed to start at offset 2. */
} test_unpacked;

Переносимым (и сохраняющим) решением было бы просто использовать массив:

struct
{
uint8_t ab[2]; /* ab[0] is guaranteed to be at offset 0. */
/* ab[1] is guaranteed to be at offset 1. */
/* other members are NOT guaranteed to start at offset 2. */
} test_packed;
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector