Выравнивание структуры C/С++

В c/С++ (я предполагаю, что они одинаковы в этом отношении), если у меня есть следующее:

struct S {
  T a;
  .
  .
  .
} s;

Гарантируется ли следующее:

(void*)&s == (void*)&s.a;

Или, другими словами, существует ли какая-либо гарантия того, что перед первым членом не будет заполнения?

Ответ 1

В C, да, это тот же адрес. Простой и понятный.


В С++ нет, это не тот же адрес. Базовые классы могут (и я подозреваю, делаю) приходить перед всеми членами, а функции виртуальных членов обычно добавляют скрытые данные в структуру где-то. Еще более запутанным, компилятор С++ может также изменять элементы по желанию, если только класс не является стандартным типом макета (хотя я не знаю, что любой компилятор делает это)

Наконец, если структура С++ состоит из стандартных типов макета, не содержит базовых классов и виртуальных функций, и все члены имеют одинаковую видимость и, возможно, другие ограничения, которые я забыл, тогда он возвращается к правилам C и требует первый член должен иметь тот же адрес, что и сам объект.

§ 9.2/7

Класс стандартного макета - это класс, который:
- не имеет нестатических элементов данных типа нестандартного макета (или массива таких типов) или ссылки,
- не имеет виртуальных функций (10.3) и нет виртуальных базовых классов (10.1),
- имеет тот же контроль доступа (раздел 11) для всех нестатических элементов данных,
- не имеет базовых классов нестандартной компоновки,
- либо не имеет нестатических членов данных в самом производном классе и не более одного базового класса с нестатическими членами данных, либо не имеет базовых классов с нестатическими членами данных и
- не имеет базовых классов того же типа, что и первый нестатический элемент данных.

§ 9.2/20

Указатель на объект структуры стандартного макета, соответствующим образом преобразованный с использованием reinterpret_cast, указывает на его начальный член (или если этот элемент является битовым полем, а затем в том элементе, в котором он находится) и наоборот. [Примечание. Таким образом, в рамках объекта структуры стандартного макета может быть указано неназванное заполнение, но не в его начале, по мере необходимости, для достижения соответствующего выравнивания. -end note]

Ответ 2

Да, это так.

Гарантируется, что перед первым элементом структуры в C и на С++ (если это POD) нет прописных букв.

C quote:

(C11, 6.7.2.1p15) "В объекте структуры может быть неназванное заполнение, но не в начале".

С++ quote:

(С++ 11, 9.2p20) "Таким образом, может существовать неназванное заполнение внутри объекта структуры стандартного макета, но не в его начале, по мере необходимости для достижения соответствующего выравнивания"