提问人:Thibault de Villèle 提问时间:11/29/2019 最后编辑:Thibault de Villèle 更新时间:11/29/2019 访问量:140
默认情况下,结构体内存的结构体在 C++ 中是如何排列的?
How is a struct of struct's memory arranged by default in C++?
问:
如果我想在 C++ 中定义一个类,例如用于 OpenGL 渲染,我喜欢这样做的方式,而且似乎也是最方便的,是首先定义一个类:Matrix
Vector
class vec3 {
double x;
double y;
double z;
[ ... ]
}
class vec4 {
double x;
double y;
double z;
double w;
[ ... ]
}
现在,据我了解,当我创建一个 vec{3|4}(右???)时,的值应该在内存中是连续的。x, y, z{, w}
如果我这样创建我的矩阵:
class mat3 {
vec3 _m[3];
[ ... ]
}
class mat4 {
vec4 _m[4];
[ ... ]
}
矩阵类中每个向量的值在内存中总是彼此相邻吗?如果我将第一个元素的地址交给 OpenGL,它读取内存中接下来的 16 个值(对于 4x4 矩阵),它会按顺序读取矩阵的 16 个值,还是来自程序中其他地方的其他信息会妨碍?x, y, z{, w}
编辑(2019 年 11 月 29 日):更正了错别字
答:
矩阵类中每个向量的 x、y、z{、w} 的值在内存中是否总是彼此相邻?
语言可能无法保证如此,但在实践中可能是连续的。
它会读取矩阵的 16 个值吗?
在 C++ 中未定义对成员进行索引的行为。API 可能是用 C 语言编写的,它可能有不同的规则。
有一个数据结构可以迭代,并保证有 16 个相邻元素:16 个双精度数组。
评论
稳健的解决方案是从 .对于编译器来说,它只是表示 的偏移量的一种方式,而您希望它为 1。你可以通过写作来实现同样的目标double[16]
&vec3::y
y
struct vec3 {
double* base;
double& x() { return *base; }
double& y() { return *(base+1); }
double& z() { return *(base+2); }
};
struct mat3 {
double values[9];
vec3 operator[](size_t s) { return vec3{values+3*s}; }
};
它都是内联的,因此编译器仍然可以静态计算偏移量。使用 时,不会在运行时调用函数。y()
评论
该标准允许任意填充,因此从技术上讲,成员在内存中是否连续是实现定义的。不过,我不知道有任何实现会为您的情况做一些意想不到的事情,所以您只需添加一个 .static_assert(sizeof(vec3) == 3 * sizeof(double));
同样,在代码中访问一堆成员,就好像它们是一个数组一样(即通过指针算术)是标准未定义的行为,因为那里没有实际的数组对象。现在,如果你给 OpenGL 这个在正确位置有值的东西,应该没有问题(因为你的编译器大概不会接触 OpenGL 代码,而 OpenGL 只关心字节是否是它们应该的样子)。struct
但请注意,对于我要说的课程范围来说,这只是“好的”。对于实际的生产代码,这些假设太脆弱,应该首选更健壮(但可能不太方便)的方法。
评论
OpenGL Mathematics (GLM)
struct vec3 { float xyz[3]; constexpr vec(float x, float y, float x) : xyz( {x,y,z} ) noexcept {} float x() const noexcept { return xyz[0];} ... }
static_assert(sizeof(vec3) == 3 * sizeof(double));