类型和未定义行为之间的指针转换

时间:2015-08-20 02:31:08

标签: c++ casting undefined-behavior

在C ++中,如果AB是不同的类,那么将A*强制转换为B*然后取消引用(即给定

A *a = ...;

是未定义的行为
((B*)a)->x

即使发生这种情况,x在两个类中都有相同的类型和偏移量。

另一方面,char*特别豁免施法规则。这是否意味着如果你这样写的话,它的定义是否明确?

((B*)(char*)a)->x

1 个答案:

答案 0 :(得分:3)

此问题取决于AB的类型。

如果BA的基类,或AB的基类,则((B *)a)是静态广播,因此{如果((B *)a)->x是基类,则{1}}是正确的;或者如果B是派生类,B实际上指向a类型对象的A部分。

如果BA是不相关的类型,那么我们必须查看严格别名规则。这是一些具体的代码:

B

假设断言通过,我们知道struct A { int p,q,r; } a; struct B { int z,y; } b; static_assert( sizeof a == 3 * sizeof(int) ); static_assert( sizeof b == 2 * sizeof(int) ); 必须指定与((B *)&a)->y相同的内存位置。

这里有两种思想流派:

  1. a.q((B *)&a)->y类型的左值,inta.q类型的对象。 intint兼容,因此不存在别名冲突。

  2. 评估int表示((B *)&a)->y,它首先评估(*(B *)&a).y,这违反了严格的别名规则,因为*(B *)&a未指定包含{{{1}的内存位置1}}。

  3. 我个人跟(1)一起去;我不认为案例2中的评估被视为“访问”,严格的别名规则谈到“访问”:

      

    如果程序试图通过以下类型之一以外的glvalue 访问对象的存储值,则行为未定义:

    然而,有一个灰色区域,因为虽然阅读*(B *)&a访问B对象的存储值;目前尚不清楚它是否也被视为访问包含该对象的结构的存储值的一部分。

    ((B *)&a)->y对后一种情况没有任何影响,我们最终仍然得到了int类型的左值。在继承的情况下,如果它是多重继承,那么这可能会破坏代码,因为它将((B*)(char*)a)->x变为int