Выравнивание и размер примитивных типов C ++

В C ++ кажется, что для всех целочисленных типов (int, long long int, std::uint16_t, …) и для типов с плавающей точкой, это всегда sizeof(T) == alignof(T),

Этот компилятор / платформа специфичен или гарантированно будет верным? Может ли быть платформа, где int32_ts не должны быть выровнены по 32-битной границе (если они не перекрываются)?

2

Решение

Для основных типов 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 ++ не требует, чтобы реализация имела стек вызовов функций. Это требует поддержки рекурсии, и есть нечто, называемое «разматывание стека», которое происходит, когда создаются исключения, но все тщательно написано, чтобы вы мог реализовать это с помощью чего-то другого, кроме линейных стеков, с которыми мы все знакомы.

9

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

Других решений пока нет …

По вопросам рекламы [email protected]