输入punning,char []和解除引用

时间:2012-04-03 01:07:21

标签: c++ type-punning

我有一个旨在存储用户定义数据(即来自插件)的结构。它有一个具有给定最大大小的char[]来存储该数据。

struct A
{
    // other members omitted
    // data meant to be type punned, only contains PODs
    char data[256];
};

然后有一个示例用户结构,它具有静态函数以从A投射自己。

struct B
{
    int i;
    double d;

    static B& FromA_ref(A& a)
    {
        // static_assert that sizeof(B) < sizeof(A::data)
        return * reinterpret_cast<B*>(a.data);
    }
};

我使用g++ -O3 -std=c++0x -Wall -o test test.cpp(GCC 4.6.1)编译。

这会触发dereferencing type-punned pointer will break strict-aliasing rules警告。我认为这样就行了,因为我使用char[]作为存储,我认为它将遵循与char*相同的规则。我觉得很奇怪,事实并非如此。不是吗?好吧,......我现在无法改变它,所以让我们继续前进。

现在让我们考虑以下方法:

struct B
{
    ....
    static B* FromA_ptr(A& a)
    {
        // static_assert that sizeof(B) < sizeof(A::data)
        return reinterpret_cast<B*>(a.data);
    }
}

由于我在这里没有取消引用任何内容,GCC不会输出任何警告。当我稍后使用指针B时,它也不会。

A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.

但这样做是否安全?我觉得我一直在解决问题而不是解决问题。对我来说->仍然以某种方式取消引用该变量。

或者,有没有更好的方法来实现这种效果? I.E.从另一个结构中的存储中获取一个可修改的引用(或指针)? (由于定义A时存储的类型集不可知,因此联合将无法工作,而某些类型可能通过插件添加,memcpy会强制我来回复制数据似乎是迄今为止唯一安全的方式)

1 个答案:

答案 0 :(得分:4)

答案是否定的,不安全(见SO question

  

GCC将假设指针不能别名。例如,如果您通过一个进行分配然后从另一个进行读取,GCC可以作为优化对读取和写入进行重新排序 - 我已经在生产代码中看到了这种情况,调试起来并不愉快。

     所使用的类型的

属性(( may_alias ))可能是最接近禁用特定代码段假设的。