【发布时间】:2015-05-30 10:32:28
【问题描述】:
这是一个严格的别名问题,因为编译器会导致任何优化顺序问题。
假设我在struct XMFLOAT3 中有三个公共floats(与this one 不同。)我想转换为float*。这会让我陷入优化问题吗?
XMFLOAT3 foo = {1.0f, 2.0f, 3.0f};
auto bar = &foo.x;
bar[2] += 5.0f;
foo.z += 5.0f;
cout << foo.z;
我假设这将始终打印“13”。但是这段代码呢:
XMFLOAT3 foo = {1.0f, 2.0f, 3.0f};
auto bar = reinterpret_cast<float*>(&foo);
bar[2] += 5.0f;
foo.z += 5.0f;
cout << foo.z;
我相信这是合法的,因为根据http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
T2 是聚合类型或联合类型,它将上述类型之一作为元素或非静态成员(递归地包括子聚合的元素和所包含联合的非静态数据成员):这使得它可以安全地从结构的第一个成员和联合的元素转换到包含它的结构/联合。
我的理解正确吗?
显然这将成为依赖于XMFLOAT3声明的实现。
【问题讨论】:
-
结构体可能包含填充不是问题吗?从编译器开始放入实际的填充将是一个迂回的举动,但优化器可能会假设这样的填充不能被正确的代码检测到。此外,
(&foo.x)[2]看起来像是一个普通的越界数组访问,这对编译器来说是显而易见的。 -
@MSalters,是的,可能会有填充,尽管在理论上和实践中填充只会出于对齐目的而添加,并且三个相邻的浮动成员将与 a 的三个元素对齐
float[3],所以它确实是狡猾的。(&foo.x)[2]等价于*(&foo.x + 2)并且只要该地址确实有一个float,3.9.2/3 就会使其格式正确,这又回到了填充和对齐。 -
@MSalters 似乎Jonathan Wakely 的答案中的
static_assert可用于防止笨拙的编译器。 (无意冒犯啮齿动物。) -
@JonathanWakely:“这可能是为了对齐”不是一个详尽的列表。如果意图是只允许用于对齐的填充,则该语句将大致是“不应有初始填充。除了满足直接在此类填充之后的成员的对齐要求外,其他任何地方都不应有填充”。
-
@JonathanMee 从第一个成员事物中添加了该索引的欺骗。
标签: c++ arrays struct alias reinterpret-cast