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

J.N*_*.N. 5 c++ type-punning

我有一个旨在存储用户定义数据(即从插件)的结构.它具有这样的char[]具有给定最大尺寸的存储该数据.

struct A
{
    // other members omitted
    // data meant to be type punned, only contains PODs
    char data[256];
};
Run Code Online (Sandbox Code Playgroud)

然后是一个示例用户结构,它具有一个静态函数来自己投射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);
    }
};
Run Code Online (Sandbox Code Playgroud)

我编译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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.
Run Code Online (Sandbox Code Playgroud)

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

或者,有没有更好的方法来实现这种效果?IE从另一个结构中的存储中获取可修改的引用(或指针)?(Union将无法工作,因为存储的类型集在A定义时是未知的,有些可能通过插件添加,memcpy会迫使我来回复制数据,尽管它似乎是目前唯一安全的方式)

Att*_*ila 4

答案是否定的,它不安全(请参阅这个SO问题

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

使用的类型上的属性(( may_alias )) 可能是最接近禁用特定代码部分的假设的。