考虑以下简单结构:
struct A
{
float data[16];
};
我的问题是:
假设一个平台float
是 32 位 IEEE754 浮点数(如果这很重要),C++ 标准是否保证预期的内存布局struct A
?如果不是,它保证什么和/或执行保证的方法是什么?
通过预期的内存布局,我的意思是结构占用16*4=64
内存中的字节,每个连续的字节被数组中的4
一个字节占用。换句话说,预期的内存布局意味着以下测试通过:float
data
static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
(offsetof
这里是合法的,因为A
是标准布局,见下文)
万一这让您感到困扰,测试实际上通过gcc 9 HEAD 的 wandbox。我从来没有遇到过一个平台和编译器的组合可以提供这个测试可能失败的证据,如果它们确实存在,我很想了解它们。
为什么有人会关心:
- 类似 SSE 的优化需要一定的内存布局(和对齐,我在这个问题中忽略了它,因为它可以使用标准
alignas
说明符来处理)。 - 这种结构的序列化可以简单地归结为一个漂亮且可移植的
write_bytes(&x, sizeof(A))
. - 一些API(例如OpenGL,特别是glUniformMatrix4fv)期望这种精确的内存布局。当然,可以只传递指向
data
数组的指针来传递这种类型的单个对象,但是对于这些序列(例如,用于上传矩阵类型顶点属性),仍然需要特定的内存布局。
实际保证:
据我所知,这些是可以预期的struct A
:
- 这是标准布局
- 作为标准布局的结果,指向的指针
A
可以是reinterpret_cast
指向其第一个数据成员的指针(大概是?),即在第一个成员之前data[0]
没有填充。
标准未提供(据我所知)的两个剩余保证是:
- 原始类型数组的元素之间没有填充(我确信这是错误的,但我未能找到确认参考),
- 里面的数组后面没有填充。
data
struct A