首页 文章

“解除引用类型惩罚指针将破坏严格别名规则”警告

提问于
浏览
51

我使用一个代码,我将枚举*转换为int * . 像这样的东西:

enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);

编译代码(g 4.1.2)时,我收到以下警告消息:

dereferencing type-punned pointer will break strict-aliasing rules

我用Google搜索了这条消息,发现只有在严格的别名优化打开时才会发生这种情况 . 我有以下问题:

  • 如果我在代码中留下此警告,是否会生成可能错误的代码?

  • 有什么方法可以解决这个问题吗?

  • 如果没有't, is it possible to turn off strict aliasing from inside the source file (because I don' t想要为所有源文件关闭它,我不想为此源文件制作单独的Makefile规则)?

是的,我实际上需要这种别名 .

5 回答

  • 5

    为了:

    • 是的 . GCC将假设指针不能别名 . 例如,如果你通过一个分配,然后从另一个读取,GCC可以作为优化,重新排序读取和写入 - 我已经看到这发生在 生产环境 代码中,并且调试不愉快 .

    • 几个 . 您可以使用联合来表示需要重新解释的内存 . 你可以使用 reinterpret_cast . 您可以在重新解释内存的位置通过 char * 进行转换 - char * 被定义为能够对任何内容进行别名 . 您可以使用具有 __attribute__((__may_alias__)) 的类型 . 您可以使用-fno-strict-aliasing全局关闭别名假设 .

    • __attribute__((__may_alias__)) 关于所使用的类型可能是最接近禁用特定代码段的假设 .

    对于您的特定示例,请注意枚举的大小定义不正确; GCC通常使用可用于表示它的最小整数大小,因此将指向枚举的指针重新解释为整数可能会在结果整数中留下未初始化的数据字节 . 不要那样做 . 为什么不直接转换为适当大的整数类型?

  • 9

    但你为什么要这样做?如果sizeof(foo)!= sizeof(int),它将会中断 . 仅仅因为枚举就像一个整数并不意味着它被存储为一个整数 .

    所以,是的,它可能会产生“潜在的”错误代码 .

  • 2

    您可以使用以下代码来转换数据:

    template<typename T, typename F>
    struct alias_cast_t
    {
        union
        {
            F raw;
            T data;
        };
    };
    
    template<typename T, typename F>
    T alias_cast(F raw_data)
    {
        alias_cast_t<T, F> ac;
        ac.raw = raw_data;
        return ac.data;
    }
    

    用法示例:

    unsigned int data = alias_cast<unsigned int>(raw_ptr);
    
  • 10

    你看过this answer吗?

    严格别名规则使此设置非法,两个不相关的类型不能指向同一个内存 . 只有char *才有此权限 . 不幸的是你仍然可以用这种方式编写代码,也许会得到一些警告,但是编译得很好 .

  • 56

    严格别名是一个编译器选项,因此您需要将其从makefile中关闭 .

    是的,它可以生成错误的代码 . 编译器将有效地假设 foobarpi 未绑定在一起,并假设 *pifoobar 更改时不会更改 .

    如前所述,使用 static_cast 代替(并且没有指针) .

相关问题