Leo*_*nid 1 c++ undefined-behavior
以下哪些是不确定的行为:
template <class T> struct Struct { T t; };
template <class T> union Union { T t; };
template <class T> void function() {
Struct aS[10];
Union aU[10];
// do something with aS[9].t and aU[9].t including initialization
T *aSP = reinterpret_cast<T *>(aS);
T *aUP = reinterpret_cast<T *>(aU);
// so here is this undefined behaviour?
T valueS = aSP[9];
// use valueS in whatever way
// so here is this undefined behaviour?
T valueU = aUP[9];
// use valueU in whatever way
// now is accessing aS[9].t or aU[9].t now UB?
}
Run Code Online (Sandbox Code Playgroud)
是的,最近3个操作中的哪个是UB?
(我的推理:我不知道该结构,是否有任何要求使其大小与单个元素相同,但是AFAIK联合必须与该元素具有相同的大小。对齐要求我没有对于工会知道,但我猜它是相同的。对于结构我不知道,就工会而言,我猜它不是UB,但正如我所说,我真的不确定。我实际上不知道的结构)
tl; dr:上面代码中的最后两个语句将始终调用未定义的行为,只需将指向联合的指针转换为指向其成员类型之一的指针,通常就可以了,因为它实际上并没有做任何事情(最糟糕的情况是未指定) ,但绝不会出现不确定的行为;请注意:我们只是在谈论演员本身,使用演员的结果访问对象是一个完全不同的故事)。
根据T最终的结果,在这种情况下,Struct<T>可能是标准布局结构[class.prop] / 3
T *aSP = reinterpret_cast<T *>(aS);
Run Code Online (Sandbox Code Playgroud)
将是明确的,因为Struct<T>将指针相互转换的,其第一部件(它是类型的T)[basic.compound] /4.3。以上reinterpret_cast相当于[expr.reinterpret.cast] / 7
T *aSP = static_cast<T *>(static_cast<void *>(aS));
Run Code Online (Sandbox Code Playgroud)
它将调用数组到指针的转换[conv.array],导致Struct<T>*指向的第一个元素aS。然后将该指针转换为void*(通过[expr.static.cast] / 4和[conv.ptr] / 2),然后T*将其转换为,这可以通过[expr.static.cast] / 13合法:
可以将类型为“指向cv1的 指针
void”的prvalue转换为类型为“指向cv2的 指针”的prvalueT,其中T是对象类型,并且cv2是与cv1相同的cv限定或大于cv1的限定。如果原始指针值表示A内存中字节的地址,并且A不满足的对齐要求T,则未指定结果指针值。否则,如果原始指针值指向objecta,并且有一个b类型的对象T(忽略cv-qualification)可以与进行指针互换a,则结果是指向的指针b。否则,转换后指针值将保持不变。
同样,
T *aUP = reinterpret_cast<T *>(aU);
Run Code Online (Sandbox Code Playgroud)
如果Union<T>是标准布局的联合,则在C ++ 17中将得到很好的定义,并且看起来在基于当前标准草案的即将发布的C ++版本中通常具有良好的定义,其中联合及其成员之一始终是指针-interconvertible [basic.compound] /4.2
以上所有内容均无关紧要,因为
T valueS = aSP[9];
Run Code Online (Sandbox Code Playgroud)
和
T valueU = aUP[9];
Run Code Online (Sandbox Code Playgroud)
无论如何,都会调用未定义的行为。aSP[9]和aUP[9](根据定义)分别与*(aSP + 9)和[expr.sub] / 1相同。这些表达式中的指针算术服从[expr.add] / 4*(aUP + 9)
J将具有整数类型的表达式添加到P指针类型的表达式或从指针类型的表达式中减去时,结果的类型为P。
- 如果
P计算结果为空指针值并J计算为0,则结果为空指针值。- 否则,如果
P指向具有n个元素x[i]的数组对象的元素,则表达式和(其中值j)在0?i + j?n情况下指向(可能是假设的)元素,而表达式则指向(可能是-假设)元素是否为0?i?j?n。xP + JJ + PJx[i+j]P - Jx[i?j]- 否则,行为是不确定的。
aSP并且aUP不指向数组的元素。即使aSP并且aUP可以与指针互换T,您也只能访问元素0并计算假设的单元素数组的元素1(但不能访问)的地址…