C++中的结构偏移和指针安全性

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])?

Yak*_*ont 8

您的代码中没有根本错误.

如果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++方式做到这一点.

  • @ChrisBeck我认为[basic.stc.dynamic.safety]的意图是定义允许垃圾收集器做出的假设的规则.基本上,你不能混淆对象的引用,并期望它们不被垃圾收集.在您的情况下,您仍然保留对该对象的引用("a") (2认同)