c – 使用强制转换为“错误”类型的指针算法
我有一个结构数组,我有一个指向其中一个结构的成员的指针.我想知道数组的哪个元素包含该成员.这有两种方法:
#include <array> #include <string> struct xyz { float x,y; std::string name; }; typedef std::array<xyz,3> triangle; // return which vertex the given coordinate is part of int vertex_a(const triangle& tri,const float* coord) { return reinterpret_cast<const xyz*>(coord) - tri.data(); } int vertex_b(const triangle& tri,const float* coord) { std::ptrdiff_t offset = reinterpret_cast<const char*>(coord) - reinterpret_cast<const char*>(tri.data()); return offset / sizeof(xyz); } 这是一个测试驱动程序: #include <iostream> int main() { triangle tri{{{12.3,45.6},{7.89,0.12},{34.5,6.78}}}; for (const xyz& coord : tri) { std::cout << vertex_a(tri,&coord.x) << ' ' << vertex_b(tri,&coord.x) << ' ' << vertex_a(tri,&coord.y) << ' ' << vertex_b(tri,&coord.y) << 'n'; } } 两种方法都产生了预期的结果: 0 0 0 0 1 1 1 1 2 2 2 2 但它们是有效的代码吗? 特别是我想知道vertex_a()是否可能通过将float * y强制转换为xyz *来调用未定义的行为,因为结果实际上并不指向struct xyz.那个问题导致我写了vertex_b(),我认为这是安全的(是吗?). 这是GCC 6.3使用-O3生成的代码: vertex_a(std::array<xyz,3ul> const&,float const*): movq %rsi,%rax movabsq $-3689348814741910323,%rsi ; 0xCCC...CD subq %rdi,%rax sarq $3,%rax imulq %rsi,%rax vertex_b(std::array<xyz,float const*): subq %rdi,%rsi movabsq $-3689348814741910323,%rdx ; 0xCCC...CD movq %rsi,%rax mulq %rdx movq %rdx,%rax shrq $5,%rax 解决方法
两者都不符合标准.
在vertex_a中,您可以将指向xyz :: x的指针转换为指向xyz的指针,因为它们是pointer-interconvertible:
但你不能从指向xyz :: y的指针转换为指向xyz的指针.该操作未定义. 在vertex_b中,你要减去两个指向const char的指针.该操作在[expr.add]中定义为:
您的表达式不指向char数组的元素,因此行为未定义. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |