C++ 17(expr.add/4)说:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式P指向具有n个元素的数组对象x的元素x [i],则表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x [i + j]如果0≤i+j≤n; 否则,行为未定义.同样地,如果0≤i-j≤n,则表达式P-J指向(可能是假设的)元素x [i-j]; 否则,行为未定义.
struct Foo {
float x, y, z;
};
Foo f;
char *p = reinterpret_cast<char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
Run Code Online (Sandbox Code Playgroud)
该行标有(*)UB?reinterpret_cast<char*>(&f)不指向char数组,而是指向浮点数,因此根据引用的段落它应该是UB.但是,如果它是UB,那么它offsetof的用处将是有限的.
是UB吗?如果没有,为什么不呢?
根据有关C++11/14严格别名规则的stackoverflow答案:
如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:
对象的动态类型,
对象动态类型的 cv 限定版本,
- 与对象的动态类型类似的类型(如 4.4 中定义),
- 与对象的动态类型相对应的有符号或无符号类型,
- 与对象动态类型的 cv 限定版本相对应的有符号或无符号类型,
- 聚合或联合类型,其元素或非静态数据成员中包括上述类型之一(递归地包括子聚合或包含的联合的元素或非静态数据成员),
- 是对象动态类型的(可能是 cv 限定的)基类类型的类型,
- a
char或unsigned char类型。
我们可以使用以下方式访问其他类型的存储吗
(1)char *
(2)char(&)[N]
(3)std::array<char, N> &
不依赖于未定义的行为?
constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e;
// a.k.a. Clockwise-Rotated Endian which allocates like
// char[8] = { n,a,i,d,n,e,\0,\0 }
const auto& arr = // std::array<char,8> &
reinterpret_cast<const std::array<char,8> &> (lil_endian);
const auto& carr = // char(&)[8]>
reinterpret_cast<const char(&)[8]> (lil_endian);
const auto* …Run Code Online (Sandbox Code Playgroud)