C++ 基本类型的对齐和大小

Alignment and size of C++ primitive types

在 C++ 中,似乎对于所有整数类型(intlong long intstd::uint16_t、...)和浮点类型,它总是 sizeof(T) == alignof(T).

这是compiler/platform-specific,还是保证是真的?是否有一个平台 int32_t 不需要在 32 位边界上对齐(只要它们不重叠)?

对于基本类型,alignof(T) == sizeof(T) 对于大多数现代 ABI 都是正确的,但不能保证是正确的。 C++ 标准让对齐主要由实现定义,仅受这些约束(参见 [basic.align][basic.fundamental] 在 C++11 中):

  • alignof(T) <= sizeof(T)。这在标准中并不明确,但数组元素之间从来没有任何填充,因此无论 T t[2] 的第一个元素对齐如何, 第二个 元素对齐不能大于 sizeof(T),因此这是 type T 的最大对齐。注意 variable 的对齐可以更大,例如,如果在其上使用 alignas

  • alignof(T) <= alignof(std::max_align_t),除非可能存在 alignasalignas 是否会导致 "over-alignment"(比 max_align_t 更细粒度)是实现定义的。

  • charsigned charunsigned char 都有相同的对齐要求(即 1,因为 sizeof(char) == 1 按照定义)。

  • 所有无符号整数类型与对应的有符号整数类型具有相同的对齐要求。

  • wchar_tchar16_tchar32_t 与其 "underlying" 整数类型具有相同的对齐要求。

历史 ABI 的基本类型与其大小不一致。一个众所周知的例子是 80386 的原始 System V ABI 中的 doublelong double,尽管分别为 8 字节和 12 字节宽,但它们仅对齐到 4 字节粒度。这是因为 堆栈指针 只能保证对齐到 4 字节的粒度,并且将激活记录中的内容对齐到比堆栈指针更大的粒度是一件痛苦的事情。1

如今,同样的堆栈对齐问题可能会出现在向量类型上;例如,在 x86-64 上,堆栈指针保证与 16 字节边界对齐,但硬件现在最多支持 512-bit (64-byte) vectors.

这些是我个人所知道的唯一反例。然而,当我得知用于内存受限嵌入式环境的 ABI 指定 no 对齐 anything(即 alignof(T) == 1 对所有 T)。 CPU 处理它并不像以前那么难,尤其是在不涉及内存虚拟化的情况下。


1 有趣的事实:C++ 标准 要求实现具有函数调用堆栈。它需要对递归的支持,当抛出异常时会发生一些叫做 "stack unwinding" 的事情,但是一切都经过精心编写,以便您 可以 使用线性堆栈以外的东西来实现它我们都很熟悉。