将指向结构体的指针强制转换为数组指针是否有效?

5

假设有一个聚合结构体/类,其中每个成员变量都是相同的数据类型:

struct MatrixStack {
    Matrix4x4 translation { ... };
    Matrix4x4 rotation { ... };
    Matrix4x4 projection { ... };
} matrixStack;

将其转换为其成员数组有多有效?例如:

const Matrix4x4 *ptr = reinterpret_cast<const Matrix4x4*>(&matrixStack);
assert(ptr == &matrixStack.translation);
assert(ptr + 1 == &matrixStack.rotation);
assert(ptr + 2 == &matrixStack.projection);
auto squashed = std::accumulate(ptr, ptr + 3, identity(), multiply());

我这样做是因为在大多数情况下,我需要使用命名成员访问来提高代码的清晰度,而在其他一些情况下,我需要将数组传递给其他API。通过使用reinterpret_cast,我可以避免分配内存。


我的理解是,使用强制类型转换的结果,除非使用reinterpret_cast,否则几乎总是存在未定义行为的风险。这种特殊情况可能会按预期工作(除非编译器混淆了结构体对齐方式,使得Matrix4x4成员在内存中不完全连续),但这仍然不能被标准保证。 - antred
可能会起作用,也可能不会,这取决于Matrix4x4的实际大小和数据对齐设置。 - Anton Malyshev
结构体可以有填充,而数组从不具有填充。 - sashoalm
@antred,假设Matrix4x4与int对齐(我确实可以控制这一点),并且该结构体严格非虚拟,那么编译器在第一个成员之前和成员之间进行填充的好理由是什么?这不是一个修辞问题,我只是想知道是否存在这样的情况。 - Ben
1个回答

3

演员不必按标准工作。

然而,你可以使用静态断言使你的代码更安全,如果假设被违反,它将阻止编译:

static_assert(sizeof(MatrixStack) == sizeof(Matrix4x4[3]), "Size mismatch.");
static_assert(alignof(MatrixStack) == alignof(Matrix4x4[3]), "Alignment mismatch.");
// ...
const Matrix4x4* ptr = &matrixStack.translation;
// or
auto &array = reinterpret_cast<const Matrix4x4(&)[3]>(matrixStack.translation);

1
你是不是想在两个sizeof/alignof参数之间使用== - Aaron McDaid
也许可以添加一个检查,即 offsetof(MatrixStack, translation)==0。第一个元素是否始终保证具有偏移量为零?我们可以检查另外两个成员是否具有预期的偏移量。 - Aaron McDaid
1
使用静态断言进行验证是很不错的选择。谢谢Maxim。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接