C++ 基本类型的对齐和大小
Alignment and size of C++ primitive types
在 C++ 中,似乎对于所有整数类型(int
、long long int
、std::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)
,除非可能存在 alignas
。 alignas
是否会导致 "over-alignment"(比 max_align_t
更细粒度)是实现定义的。
char
、signed char
和 unsigned char
都有相同的对齐要求(即 1,因为 sizeof(char) == 1
按照定义)。
所有无符号整数类型与对应的有符号整数类型具有相同的对齐要求。
wchar_t
、char16_t
和 char32_t
与其 "underlying" 整数类型具有相同的对齐要求。
曾 历史 ABI 的基本类型与其大小不一致。一个众所周知的例子是 80386 的原始 System V ABI 中的 double
和 long 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" 的事情,但是一切都经过精心编写,以便您 可以 使用线性堆栈以外的东西来实现它我们都很熟悉。
在 C++ 中,似乎对于所有整数类型(int
、long long int
、std::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)
,除非可能存在alignas
。alignas
是否会导致 "over-alignment"(比max_align_t
更细粒度)是实现定义的。char
、signed char
和unsigned char
都有相同的对齐要求(即 1,因为sizeof(char) == 1
按照定义)。所有无符号整数类型与对应的有符号整数类型具有相同的对齐要求。
wchar_t
、char16_t
和char32_t
与其 "underlying" 整数类型具有相同的对齐要求。
曾 历史 ABI 的基本类型与其大小不一致。一个众所周知的例子是 80386 的原始 System V ABI 中的 double
和 long 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" 的事情,但是一切都经过精心编写,以便您 可以 使用线性堆栈以外的东西来实现它我们都很熟悉。