C ++:reinterpret_cast的奇怪行为

时间:2016-07-13 10:41:59

标签: c++ casting

我有以下代码段

#include <iostream>

using namespace std;

class foobar
{
    public:
    unsigned int a = 97;
    unsigned int b = 98;
    unsigned int c = 99;
};


class barfoo
{
    public:
    char a:32,b:32,c;

};


int main(){
    foobar * f = new foobar();
    barfoo * b = (reinterpret_cast<barfoo *>(f));
    cout << b->a << "-" << b->b << "-" << b->c;

}

输出:

a-b-c

但是,如果我在barfoo中指定c的宽度,则它不起作用(所有值都为0)。观察

#include <iostream>

using namespace std;

class foobar
{
    public:
    unsigned int a = 97;
    unsigned int b = 98;
    unsigned int c = 99;
};


class barfoo
{
    public:
    char a:32,b:32,c:32;

};


int main(){
    foobar * f = new foobar();
    barfoo * b = (reinterpret_cast<barfoo *>(f));
    cout << b->a << "-" << b->b << "-" << b->c;

}

输出:

--

字符都是0

知道为什么会这样吗?

链接到ideone first snippet - 工作

Linke to ideone second snippet - 不工作

编译器是gcc-5.1 谢谢!

2 个答案:

答案 0 :(得分:4)

reinterpret_cast不符合已定义行为的要求,因此虽然可以接受b的任何后续访问,但其结果的分配是未定义的行为:

barfoo * b = (reinterpret_cast<barfoo *>(f));

reinterpret_cast必须满足以下条件之一,其中foobar是DynamicType,barfoo是AliasedType:

  
      
  • AliasedType是(可能是cv限定的)DynamicType
  •   
  • AliasedType和DynamicType都是(可能是多级,可能是每个级别的cv限定)指向相同类型的指针T
  •   
  • AliasedType是DynamicType
  • 的(可能是cv限定的)有符号或无符号变体   
  • AliasedType是一种聚合类型或联合类型,它将上述类型之一保存为元素或非静态成员(包括递归地,包含联合的子聚合和非静态数据成员的元素):这使得它在给定指向其非静态成员或元素的指针的情况下,可以安全地获取指向结构或联合的可用指针。
  •   
  • AliasedType是(可能是cv限定的)DynamicType
  • 的基类   
  • AliasedType为charunsigned char:这允许将任何对象的对象表示检查为unsigned char数组。
  •   

由于AliasedType不属于任何这些条件,因此访问reinterpret_cast的结果是未定义的行为。

答案 1 :(得分:2)

首先,检查2个类是否大小相同。可以想象,填充和对齐可能使位域a,b和c的位置与正常成员a,b和c等的位置不同。为什么使用char作为32位位域?我的编译器警告位域超出类型的大小。

否则(如果你为barfoo类更改了char为unsigned int),无论你有什么标准-UB,reinterpret_cast和access都有很好的工作机会。如果你通过一个联盟使用良好支持和完善的类型惩罚成语,可能更是如此。

通过联合进行类型惩罚是告诉编译器'这些不同类型的2个指针可能是别名的一种方式,不要进行根本优化,假设它们可能不是别名'。