在 C++ 中,似乎对于所有整数类型(int
、long long int
、std::uint16_t
、 ...)和浮点类型,它总是sizeof(T) == alignof(T)
.
这个编译器/平台是特定的,还是保证是真的?是否存在一个平台,其中int32_t
s 不需要在 32 位边界上对齐(只要它们不重叠)?
在 C++ 中,似乎对于所有整数类型(int
、long long int
、std::uint16_t
、 ...)和浮点类型,它总是sizeof(T) == alignof(T)
.
这个编译器/平台是特定的,还是保证是真的?是否存在一个平台,其中int32_t
s 不需要在 32 位边界上对齐(只要它们不重叠)?
对于基本类型,alignof(T) == sizeof(T)
对于大多数现代 ABI 来说都是正确的,但不能保证它是正确的。C++ 标准主要是实现定义的对齐方式,仅受这些约束(参见C++11 中的[basic.align]和[basic.fundamental] ):
alignof(T) <= sizeof(T)
. 这在标准中没有明确说明,但数组元素之间永远不会有任何填充,因此无论 的第一个元素的对齐方式如何T t[2]
,第二个元素的对齐方式都不能大于sizeof(T)
,因此这是类型的最大对齐方式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。一个著名的例子是80386double
的long double
原始 System V ABI,尽管分别为 8 和 12 字节宽,但它仅与 4 字节粒度对齐。这是因为堆栈指针只能保证对齐到 4 字节的粒度,并且将激活记录中的内容对齐到比堆栈指针更大的粒度是很痛苦的。1
如今,同样的堆栈对齐问题可能会出现向量类型;例如,在 x86-64 上,堆栈指针保证与 16 字节边界对齐,但硬件现在最多支持512 位(64 字节)向量。
这些是我个人知道的唯一反例。但是,如果得知内存受限的嵌入式环境的 ABI 没有指定任何对齐(即所有 T),我不会感到惊讶。CPU 不再像过去那样难以处理,尤其是在不涉及内存虚拟化的情况下。alignof(T) == 1
1有趣的事实:C++ 标准不要求实现具有函数调用堆栈。它需要对递归的支持,并且在抛出异常时会发生称为“堆栈展开”的事情,但是所有内容都经过精心编写,以便您可以使用我们都熟悉的线性堆栈以外的东西来实现它。