严格别名规则:static_cast vs reinterpret_cast

时间:2017-04-22 03:44:30

标签: c++ casting undefined-behavior

考虑源类型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。

2 个答案:

答案 0 :(得分:2)

在C ++ 14(expr.reinterpret.cast / 7)中,如果sD正确对齐,则reinterpret_cast<D *>(s)的定义为static_cast<D *>(static_cast<void *>(s))。所以你的两个案例完全相同。

如果存在对齐违规,则未指定强制转换的结果,  意味着如果结果被取消引用,它实际上是未定义的行为。

注意:由于各种原因,后续// use d可能是未定义的行为;但如果是这样的话,那么它在两种情况下都是未定义的,或者在两种情况下都是相同的明确定义的行为。你在标题中提到了“严格别名”,但严格的别名问题仅适用于*d,而不适用于演员本身。

在C ++ 11中,要求SD都是标准布局类型,否则结果是未指定的。

在C ++ 03中,只定义了如果sD正确对齐,则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。