Гарантирует ли стандарт С++ 11, что все компиляторы будут выбирать одинаковые смещения памяти для всех членов данной стандартной структуры макета, предполагая, что все члены имеют гарантированные размеры (например, int32_t
вместо int
)?
То есть гарантирует ли C++11 для данного члена стандартной структуры макета, что offsetof
будет давать одинаковое значение во всех компиляторах?
Если да, есть ли какая-либо спецификация того, каким будет это значение, например. как функция размера, выравнивания и порядка членов структуры?
Нет гарантии, что offsetof даст одинаковые значения для разных компиляторов.
Существуют гарантии относительно минимальных размеров типов (например, char
>= 8 бит, short
, int
>= 16 бит, long
>= 32 бит, long long
>= 64 бит) и отношения между размерами 1 (sizeof(char)
<= sizeof(short)
< = sizeof(int)
<= sizeof(long)
<= sizeof(long long)
).
Для большинства типов гарантируется, что требования к выравниванию не превышают размер типа.
Для любого struct
/class
первый (нестатический2) элемент должен быть в начале class
/struct
, и при отсутствии изменений видимости порядок гарантированно будет в порядке определения. Например:
struct { // same if you use `class`
int a;
int b;
};
Поскольку они оба общедоступны, a
и b
должны быть в таком порядке. Но:
struct {
int a;
int b;
private:
int c;
};
Первый элемент (a
) должен находиться в начале структуры, но из-за замены public
на private
компилятору (теоретически) разрешено размещать c
перед b
.
Хотя это правило со временем менялось. В C++98 даже пустой спецификатор видимости позволял переупорядочивать члены.
struct A {
int a;
int b;
public:
int c;
};
public
позволяет переставлять b
и c
, даже если они оба общедоступны. С тех пор он был ужесточен, так что это только элементы с разной видимостью, а в C++ 23 вся идея перестановки элементов на основе видимости ушла (и, по моему мнению, уже давно - я не думаю, что кто-то когда-либо использовал это, так что это всегда было правилом, которое вам нужно было знать, но оно никому не помогало).
@Aconcagua С C++ 23 это ограничение на тот же контроль доступа будет снято.
Нет, таких гарантий нет. Стандарт C++ явно предусматривает требования к заполнению и выравниванию для конкретного типа, во-первых, и это автоматически отменяет такого рода гарантии.
Было бы разумно предусмотреть единые требования к заполнению и выравниванию для конкретной аппаратной платформы, которые будут реализованы всеми компиляторами на этой платформе, но это опять же не гарантируется.
Мало того, что нет никаких гарантий, но на самом деле разные компиляторы действительно делают разные выборы на одних и тех же платформах (например, Microsoft C++ и, по крайней мере, некоторые порты gnu C++ используют разные размеры для bool
на одном и том же оборудовании и ОС).
Компиляторы (или порты) делают разные выборы даже на одной и той же платформе по целому ряду причин (например, адаптация для лучшей поддержки встроенных). Некоторые компиляторы также предоставляют ряд параметров компиляции, которые явно или неявно влияют на выбор, связанный с размерами, выравниванием типов или (внутри структур) заполнением.
Точно нет. Расположение памяти полностью зависит от реализации C++. Единственным исключением, только для классов стандартной компоновки, является то, что первый нестатический член данных или подобъект(ы) базового класса имеют нулевое смещение. Существуют также некоторые другие ограничения, например. из-за размеров и выравнивания подобъектов и ограничений на порядок адресов подобъектов, но ничего, что определяет конкретные смещения подобъектов.
Однако, как правило, компиляторы следуют некоторым спецификациям ABI для любой данной архитектуры/платформы, так что компиляторы для той же архитектуры/платформы, скорее всего, будут использовать один и тот же ABI и одинаковую структуру памяти (например, SysV x86-64 ABI вместе с Itanium C++ ABI в Linux). x86-64 по крайней мере для GCC и Clang).
Смещение элемента также зависит от выравнивания и заполнения, которые зависят от платформы (а также от типов элементов). Вы можете добиться большей согласованности, если компилятор упаковывает элементы или вставляете элементы заполнения (вместо компилятора).