2012-04-03 71 views
5

我有一个旨在存储用户定义的数据(即从一个插件)的结构。它有一个这样的char[]与给定的最大大小来存储该数据。类型双引号,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.从另一个结构中的存储获得一个可修改的引用(或指针)? (Union不起作用,因为当定义了A时,存储的类型集是不知道的,有些可能通过插件添加,memcpy将迫使我来回复制数据,尽管它似乎是唯一安全的方式远)

+0

我不是专家,但你在寻找'__may_alias__'属性吗? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html – 2012-04-03 01:14:36

+0

无论如何,你如何处理对齐问题? – curiousguy 2012-07-11 07:12:56

+0

@curiousguy:到目前为止我不,但我应该。尽管如此,在x86上我猜我可能会降低性能。我希望'__attribute __((aligned(8)));'因为我不想自动向量化任何东西,所以就够了。可能'may_alias'已经告诉GCC在做太多奇怪的事情之前要注意对齐。 – 2012-07-12 06:21:26

回答

3

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

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

属性((may_alias))可能是你可以得到禁止用于特定的代码段的假设最接近的一次。