C++ “取消引用类型双关指针将破坏严格别名规则”警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4163126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:40:44  来源:igfitidea点击:

"dereferencing type-punned pointer will break strict-aliasing rules" warning

c++warningsstrict-aliasing

提问by petersohn

I use a code where I cast an enum* to int*. Something like this:

我使用代码将 enum* 转换为 int*。像这样的东西:

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

When compiling the code (g++ 4.1.2), I get the following warning message:

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

dereferencing type-punned pointer will break strict-aliasing rules

I googled this message, and found that it happens only when strict aliasing optimization is on. I have the following questions:

我在谷歌上搜索了这条消息,发现只有在启用了严格的别名优化时才会发生这种情况。我有以下问题:

  • If I leave the code with this warning, will it generate potentially wrong code?
  • Is there any way to work around this problem?
  • If there isn't, is it possible to turn off strict aliasing from inside the source file (because I don't want to turn it off for all source files and I don't want to make a separate Makefile rule for this source file)?
  • 如果我留下带有此警告的代码,它会生成潜在的错误代码吗?
  • 有没有办法解决这个问题?
  • 如果没有,是否可以从源文件内部关闭严格别名(因为我不想为所有源文件关闭它,也不想为此源文件制定单独的 Makefile 规则)?

And yes, I actually need this kind of aliasing.

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

回答by moonshadow

In order:

为了:

  • Yes. GCC will assume that the pointers cannot alias. For instance, if you assign through one then read from the other, GCC may, as an optimisation, reorder the read and write - I have seen this happen in production code, and it is not pleasant to debug.

  • Several. You could use a union to represent the memory you need to reinterpret. You could use a reinterpret_cast. You could cast via char *at the point where you reinterpret the memory - char *are defined as being able to alias anything. You could use a type which has __attribute__((__may_alias__)). You could turn off the aliasing assumptions globally using -fno-strict-aliasing.

  • __attribute__((__may_alias__))on the types used is probably the closest you can get to disabling the assumption for a particular section of code.

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

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

  • __attribute__((__may_alias__))使用的类型可能是最接近禁用特定代码部分假设的方法。

For your particular example, note that the size of an enum is ill defined; GCC generally uses the smallest integer size that can be used to represent it, so reinterpreting a pointer to an enum as an integer could leave you with uninitialised data bytes in the resulting integer. Don't do that. Why not just cast to a suitably large integer type?

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

回答by CashCow

But why are you doing this? It will break if sizeof(foo) != sizeof(int). Just because an enum is like an integer does not mean it is stored as one.

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

So yes, it could generate "potentially" wrong code.

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

回答by Markus Lenger

You could use the following code to cast your data:

您可以使用以下代码来投射数据:

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;
}

Example usage:

用法示例:

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

回答by icecrime

Have you looked into this answer?

你有没有研究过这个答案

The strict aliasing rule makes this setup illegal, two unrelated types can't point to the same memory. Only char* has this privilege. Unfortunately you can still code this way, maybe get some warnings, but have it compile fine.

严格的别名规则使这种设置非法,两个不相关的类型不能指向同一个内存。只有 char* 有这个特权。不幸的是,您仍然可以通过这种方式进行编码,也许会收到一些警告,但可以正常编译。

回答by ?imon Tóth

Strict aliasing is a compiler option, so you need to turn it off from the makefile.

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

And yes, it can generate incorrect code. The compiler will effectively assume that foobarand piaren't bound together, and will assume that *piwon't change if foobarchanged.

是的,它可以生成不正确的代码。编译器将有效地假设foobarpi不绑定在一起,并且假设*pi如果foobar更改不会更改。

As already mentioned, use static_castinstead (and no pointers).

如前所述,请static_cast改用(并且没有指针)。