“取消引用类型双关指针将违反严格别名规则”警告
我使用将 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
按顺序:
是的。 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 viachar *
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?
您可以使用以下代码来转换数据:
示例用法:
You could use the following code to cast your data:
Example usage:
但你为什么要这样做?如果 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.
您是否研究过这个答案?
Have you looked into this answer ?
严格别名是一个编译器选项,因此您需要从 makefile 中将其关闭。
是的,它可能会生成错误的代码。编译器将有效地假设
foobar
和pi
没有绑定在一起,并且假设*pi
不会改变,如果foobar 改变了。
正如已经提到的,使用
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
andpi
aren't bound together, and will assume that*pi
won't change iffoobar
changed.As already mentioned, use
static_cast
instead (and no pointers).