“取消引用类型双关指针将违反严格别名规则”警告

发布于 2024-10-02 06:08:52 字数 502 浏览 0 评论 0原文

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

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

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

dereferencing type-punned pointer will break strict-aliasing rules

我用谷歌搜索了此消息,发现只有当严格别名优化打开时才会发生这种情况。我有以下问题:

  • 如果我在代码中留下此警告,它是否会生成潜在的错误代码?
  • 有什么办法可以解决这个问题吗?
  • 如果没有,是否可以从源文件内部关闭严格别名(因为我不想为所有源文件关闭它,并且我不想为此源文件制定单独的 Makefile 规则)?

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

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

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

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

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)?

And yes, I actually need this kind of aliasing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

行至春深 2024-10-09 06:08:52

按顺序:

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

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

  • 使用类型上的

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

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

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.

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?

别想她 2024-10-09 06:08:52

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

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

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);
新一帅帅 2024-10-09 06:08:52

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

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

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.

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

你如我软肋 2024-10-09 06:08:52

您是否研究过这个答案

严格的别名规则使得这个
设置非法,两种不相关的类型
不能指向同一个内存。
char* 具有此特权

不幸的是你仍然可以编写这个代码
方式,也许会收到一些警告,但是有
它编译得很好。

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.

好菇凉咱不稀罕他 2024-10-09 06:08:52

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

是的,它可能会生成错误的代码。编译器将有效地假设 foobarpi 没有绑定在一起,并且假设 *pi 不会改变,如果 foob​​ar 改变了。

正如已经提到的,使用 static_cast 代替(并且没有指针)。

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

And yes, it can generate incorrect code. The compiler will effectively assume that foobar and pi aren't bound together, and will assume that *pi won't change if foobar changed.

As already mentioned, use static_cast instead (and no pointers).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文