“解引用types指针会打破严格别名规则”警告
我使用一个代码,我把一个枚举*到int *。 像这样的东西:
enum foo { ... } ... foo foobar; int *pi = reinterpret_cast<int*>(&foobar);
编译代码时(g ++ 4.1.2),我得到以下警告信息:
dereferencing type-punned pointer will break strict-aliasing rules
我search了这个消息,发现只有在严格的别名优化的时候才会发生。 我有以下问题:
- 如果我留下这个警告的代码,它会产生潜在的错误的代码?
- 有什么办法解决这个问题?
- 如果没有,是否可以从源文件中closures严格的别名(因为我不想closures所有的源文件,我不想为这个源文件做一个单独的Makefile规则)?
是的,我实际上需要这种别名。
为了:
-
是。 海湾合作委员会将假定指针不能别名。 例如,如果你通过一个指定然后从另一个读取,GCC可以作为一个优化,重新sorting读取和写入 – 我已经看到这发生在生产代码,并不愉快的debugging。
-
一些。 您可以使用联合来表示您需要重新解释的内存。 你可以使用
reinterpret_cast
。 你可以通过char *
重新解释内存 –char *
被定义为可以别名的地方。 您可以使用具有__attribute__((__may_alias__))
。 您可以使用-fno-strict-aliasingclosures全局假设。 -
关于所使用的types的
__attribute__((__may_alias__))
可能是最接近您可以禁用特定代码段的假设。
对于您的特定示例,请注意枚举的大小是生病定义的; GCC通常使用可用于表示它的最小整数大小,因此将枚举指针重新解释为整数可能会在结果整数中留下未初始化的数据字节。 不要这样做。 为什么不只是投到一个适当的大整数types?
但是你为什么这样做呢? 如果sizeof(foo)!= sizeof(int),它将会中断。 只是因为一个枚举像一个整数并不意味着它被存储为一个。
所以是的,它可能会产生“潜在的”错误的代码。
您可以使用以下代码来投射数据:
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);
你看过这个答案吗?
严格的别名规则使得这个设置非法,两个不相关的types不能指向相同的内存。 只有char *有这个特权 。 不幸的是,你仍然可以这样编码,也许会得到一些警告,但是编译好。
严格的别名是一个编译器选项,所以你需要把它从makefile中closures。
是的,它可以产生不正确的代码。 编译器会有效地假设foobar
和pi
没有绑定在一起,并且假定foobar
改变时*pi
不会改变。
如前所述,使用static_cast
(而不是指针)。