当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
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吗?如果没有,为什么不呢?
这是读取普通可复制对象的字节的常用方法
Object obj;
auto p = reinterpret_cast<char*>(&obj);
for(size_t i = 0; i < sizeof(obj); i++)
consume(p[i]);
Run Code Online (Sandbox Code Playgroud)
问题不在于严格别名,char*而是允许别名.问题出在[expr.add]的这段话
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式
P指向具有元素x[i]的数组对象x的n元素,则表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x[i + j]if0 ? i + j ? n; 否则,行为未定义.同样,表达式P - J指向(可能是假设的)元素x[i ? j]if0 ? i ? j ? n; 否则,行为未定义.
假设元素所指的地方
过去的阵列的最后一个元素的指针
x的n元素被认为是等效的指针的假想元件x[n]用于此目的的 …