Chr*_*eck 5 c++ pointers offsetof language-lawyer c++11
这个问题是关于使用带有结构偏移的指针算法导出的指针.
考虑以下程序:
#include <cstddef>
#include <iostream>
#include <new>
struct A {
float a;
double b;
int c;
};
static constexpr auto off_c = offsetof(A, c);
int main() {
A * a = new A{0.0f, 0.0, 5};
char * a_storage = reinterpret_cast<char *>(a);
int * c = reinterpret_cast<int *>(a_storage + off_c));
std::cout << *c << std::endl;
delete a;
}
Run Code Online (Sandbox Code Playgroud)
该程序似乎可以工作,并使用默认设置和C++ 11标准在我测试的编译器上给出预期结果.
(A密切相关的程序,在这里我们使用void *的,而不是char *和static_cast代替reinterpret_cast,没有被普遍接受.gcc 5.4发出关于与空指针的指针算术警告,并clang 6.0说,与指针算法void *是错误的.)
根据C++标准,该程序是否具有明确定义的行为?
答案取决于实现是否已放宽或严格指针安全([basic.stc.dynamic.safety])?
您的代码中没有根本错误.
如果A不是普通旧数据,则上面是UB(在C++ 17之前)并且有条件地支持(在C++ 17之后).
您可能想要替换char*和int*使用auto*,但这是一种风格的东西.
请注意,指向成员的指针以类型安全的方式完成相同的操作.大多数编译器实现了一个指向成员的指针...作为类型中成员的偏移量.然而,它们确实在任何地方工作,甚至在非吊舱结构上.
题外话:我没有看到一个保证,offsetof就是constexpr标准.;)
在任何情况下,替换:
static constexpr auto off_c = offsetof(A, c);
Run Code Online (Sandbox Code Playgroud)
同
static constexpr auto off_c = &A::c;
Run Code Online (Sandbox Code Playgroud)
和
auto* a_storage = static_cast<char *>(a);
auto* c = reinterpret_cast<int *>(a_storage + off_c));
Run Code Online (Sandbox Code Playgroud)
同
auto* c = &(a->*off_c);
Run Code Online (Sandbox Code Playgroud)
用C++方式做到这一点.