В C ++ кажется, что для всех целочисленных типов (int
, long long int
, std::uint16_t
, …) и для типов с плавающей точкой, это всегда sizeof(T) == alignof(T)
,
Этот компилятор / платформа специфичен или гарантированно будет верным? Может ли быть платформа, где int32_t
s не должны быть выровнены по 32-битной границе (если они не перекрываются)?
Для основных типов alignof(T) == sizeof(T)
верно для большинства современных ABI, но это не гарантируется, чтобы быть правдой. Стандарт C ++ оставляет выравнивание в основном определяемым реализацией, подчиняясь только этим ограничениям (см. [Basic.align] а также [Basic.fundamental] в C ++ 11):
alignof(T) <= sizeof(T)
, Это не является явным в стандарте, но между элементами массива никогда не бывает заполнения, поэтому независимо от выравнивания первого элемента T t[2]
, второй элемент не может иметь выравнивание больше чем sizeof(T)
и, следовательно, это максимальное выравнивание для тип Обратите внимание, что выравнивание переменная может быть больше, например, если alignas
используется на нем.
alignof(T) <= alignof(std::max_align_t)
за исключением, возможно, в присутствии alignas
, Будь то alignas
может вызвать «чрезмерное выравнивание» (с большей степенью детализации, чем max_align_t
) определяется реализацией.
char
, signed char
, а также unsigned char
у всех одинаковое требование выравнивания (а именно 1, потому что sizeof(char) == 1
по определению).
Все целочисленные типы без знака имеют то же требование выравнивания, что и соответствующий тип со знаком.
wchar_t
, char16_t
, а также char32_t
имеют те же требования к выравниванию, что и их «базовые» целочисленные типы.
Там иметь были исторические ABI, где фундаментальные типы не были приведены в соответствие с их размером. Один известный пример double
а также long double
в исходной ABI System V для 80386, которые были выровнены только с 4-байтовой гранулярностью, несмотря на ширину 8 и 12 байтов соответственно. Это было потому, что указатель стека было гарантировано, что он будет выровнен только с 4-байтовой гранулярностью, и очень трудно выровнять вещи в записи активации с большей гранулярностью, чем указатель стека.1
В настоящее время та же проблема выравнивания стека может возникнуть с векторными типами; например, в x86-64 указатель стека гарантированно выровнен по 16-байтовой границе, но аппаратное обеспечение теперь поддерживает до 512-битные (64-байтовые) векторы.
Это единственные контрпримеры, о которых я лично знаю. Однако меня не удивит, что ABI для встроенной среды с ограниченным объемом памяти определил нет выравнивание для что-нибудь (то есть, alignof(T) == 1
для всех T). Это не так сложно для процессора, как раньше, особенно если не задействовать виртуализацию памяти.
1 Интересный факт: стандарт C ++ не требует, чтобы реализация имела стек вызовов функций. Это требует поддержки рекурсии, и есть нечто, называемое «разматывание стека», которое происходит, когда создаются исключения, но все тщательно написано, чтобы вы мог реализовать это с помощью чего-то другого, кроме линейных стеков, с которыми мы все знакомы.
Других решений пока нет …