考虑源类型S和目标类型D,它们是无关类型但具有相同的布局(例如,S是一个简单包裹D的结构,反之亦然,或者S和D碰巧发生在具有相同顺序的相同数据成员等)。 S和D中的每一个都可以是基本类型或类类型。
(A)
S* s;
D* d = reinterpret_cast<D*>(s);
//use d
(B)
S* s;
D* d = static_cast<D*>(static_cast<void*>(s));
//use d
根据严格别名规则,我知道在执行这些强制转换时我们已经有未定义的行为 - 尽管在实践中它很可能会有效。< / p>
严格别名的规则是here。 不相关表示布局相同但违反严格别名。
我的问题是:
(A)和(B)完全等同吗?当
(1)。如上所述,S和D无关。
(2)。 S和D是相关的,因为强制转换不会违反严格的别名规则,因此不会违反UB。
答案 0 :(得分:2)
在C ++ 14(expr.reinterpret.cast / 7)中,如果s
与D
正确对齐,则reinterpret_cast<D *>(s)
的定义为static_cast<D *>(static_cast<void *>(s))
。所以你的两个案例完全相同。
如果存在对齐违规,则未指定强制转换的结果, 意味着如果结果被取消引用,它实际上是未定义的行为。
注意:由于各种原因,后续// use d
可能是未定义的行为;但如果是这样的话,那么它在两种情况下都是未定义的,或者在两种情况下都是相同的明确定义的行为。你在标题中提到了“严格别名”,但严格的别名问题仅适用于*d
,而不适用于演员本身。
在C ++ 11中,要求S
和D
都是标准布局类型,否则结果是未指定的。
在C ++ 03中,只定义了如果s
与D
正确对齐,则s == (S *)(D *)s
。没有特别要求(D *)s
可以以任何其他方式使用,而不是转回S *
。你的两个案例在C ++ 03中可能有所不同。这显然是一个令人不满意的规范。
答案 1 :(得分:0)
(1)。如上所述,S和D是不相关的。
UB,因为编译器可以在允许的限制内自由地执行任何操作(例如,针对特定于拱的优化目的)。这可能会出乎意料,但这很可能取决于结构S和D.
(2)。 S和D是相关的,使得强制转换不违反严格的混叠规则,因此不违反UB。
仍然是UB。想象一下,S和D是相关的。通过从一个转换到另一个实际的指向地址可能会改变。在重新解释转换的情况下,执行的实际代码和指向地址也保持不变。换句话说,你最终会得到无效指针,因此UB。