作者:哈喽随风amy | 来源:互联网 | 2023-02-01 20:02
我有一个结构数组,我有一个指向其中一个结构的成员的指针.我想知道数组的哪个元素包含该成员.这有两种方法:
#include
#include
struct xyz
{
float x, y;
std::string name;
};
typedef std::array triangle;
// return which vertex the given coordinate is part of
int vertex_a(const triangle& tri, const float* coord)
{
return reinterpret_cast(coord) - tri.data();
}
int vertex_b(const triangle& tri, const float* coord)
{
std::ptrdiff_t offset = reinterpret_cast(coord) - reinterpret_cast(tri.data());
return offset / sizeof(xyz);
}
这是一个测试驱动程序:
#include
int main()
{
triangle tri{{{12.3, 45.6}, {7.89, 0.12}, {34.5, 6.78}}};
for (const xyz& coord : tri) {
std::cout
<
两种方法都产生了预期的结果:
0 0 0 0
1 1 1 1
2 2 2 2
但它们是有效的代码吗?
特别是我想知道是否vertex_a()
可能通过强制转换float* y
来调用未定义的行为,xyz*
因为结果实际上并没有指向a struct xyz
.这种担忧促使我写作vertex_b()
,我认为这是安全的(是吗?).
这是GCC 6.3使用-O3生成的代码:
vertex_a(std::array const&, float const*):
movq %rsi, %rax
movabsq $-3689348814741910323, %rsi ; 0xCCC...CD
subq %rdi, %rax
sarq $3, %rax
imulq %rsi, %rax
vertex_b(std::array const&, float const*):
subq %rdi, %rsi
movabsq $-3689348814741910323, %rdx ; 0xCCC...CD
movq %rsi, %rax
mulq %rdx
movq %rdx, %rax
shrq $5, %rax
Barry..
8
两者都不符合标准.
在vertex_a
,你被允许将指针转换为xyz::x
指针,xyz
因为它们是指针可互换的:
如果一个是标准布局类对象而另一个是该对象的第一个非静态数据成员,则两个对象a和b是指针可互换的 [...]
如果两个对象是指针可互换的,那么它们具有相同的地址,并且可以通过a获得指向另一个指针的指针reinterpret_cast
.
但是你不能从指向指针xyz::y
的指针进行转换xyz
.该操作未定义.
在vertex_b
,你要减去两个指针const char
.该操作在[expr.add]中定义为:
如果表达式P
和Q
指向,分别,元件x[i]
和x[j]
同一阵列对象的x
,表达P - Q
具有值i ? j
; 否则,行为未定义
您的表达式不指向数组的元素char
,因此行为未定义.
1> Barry..:
两者都不符合标准.
在vertex_a
,你被允许将指针转换为xyz::x
指针,xyz
因为它们是指针可互换的:
如果一个是标准布局类对象而另一个是该对象的第一个非静态数据成员,则两个对象a和b是指针可互换的 [...]
如果两个对象是指针可互换的,那么它们具有相同的地址,并且可以通过a获得指向另一个指针的指针reinterpret_cast
.
但是你不能从指向指针xyz::y
的指针进行转换xyz
.该操作未定义.
在vertex_b
,你要减去两个指针const char
.该操作在[expr.add]中定义为:
如果表达式P
和Q
指向,分别,元件x[i]
和x[j]
同一阵列对象的x
,表达P - Q
具有值i ? j
; 否则,行为未定义
您的表达式不指向数组的元素char
,因此行为未定义.