【问题标题】:Type punning, char[] and dereferencing类型双关语、char[] 和取消引用
【发布时间】:2012-04-16 16:06:00
【问题描述】:

我有一个旨在存储用户定义数据(即来自插件)的结构。它有一个这样的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.

但是这样做安全吗?我觉得我一直在努力解决问题,而不是解决问题。对我来说,-&gt; 仍在以某种方式取消引用变量。

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

【问题讨论】:

  • 我不是专家,但您在寻找__may_alias__ 属性吗? blog.worldofcoding.com/2010/02/…
  • 不管怎样,对齐问题怎么处理?
  • @curiousguy :到目前为止我还没有,但我应该这样做。不过,在 x86 上,我想我可能会在最坏的情况下降低性能。我希望__attribute__((aligned(8))); 就足够了,因为我不想自动矢量化任何东西。可能,may_alias 已经告诉 GCC 在做太多奇怪的事情之前要注意对齐。
  • @curiousguy:一个简单的方法应该是union { char dat[theSize]; typeWithWorstAlignment dummy; }。这将解决所有问题,但标准没有提供解决方案的混叠问题。鉴于缺乏任何别名问题的解决方案,我觉得奇怪的是 C11 标准包含对齐指令,这些指令在涉及类型双关的情况下并不是真正有用的except

标签: c++ type-punning


【解决方案1】:

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

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

attribute((ma​​y_alias)) 可能是最接近禁用特定代码部分的假设的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2011-11-29
    相关资源
    最近更新 更多