我使用代码将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
我用Google搜索了这条消息,发现只有在严格别名优化打开时才会发生这种情况。我有以下问题:
是的,我实际上需要这种别名。
答案 0 :(得分:57)
按顺序:
是。 GCC将假设指针不能别名。例如,如果您通过一个进行分配然后从另一个进行读取,GCC可以作为优化对读取和写入进行重新排序 - 我已经在生产代码中看到了这种情况,并且调试起来并不愉快。
几个。您可以使用联合来表示需要重新解释的内存。您可以使用reinterpret_cast
。您可以在重新解释内存的位置通过char *
进行投射 - char *
被定义为能够对任何内容进行别名。您可以使用具有__attribute__((__may_alias__))
的类型。您可以使用-fno-strict-aliasing全局关闭别名假设。
__attribute__((__may_alias__))
可能是最接近禁用特定代码段假设的。
对于您的特定示例,请注意枚举的大小定义不正确; GCC通常使用可用于表示它的最小整数大小,因此将指向枚举的指针重新解释为整数可能会在结果整数中留下未初始化的数据字节。不要那样做。为什么不直接转换为适当大的整数类型?
答案 1 :(得分:11)
但你为什么要这样做?如果sizeof(foo)!= sizeof(int),它将会中断。仅仅因为枚举就像一个整数并不意味着它被存储为一个整数。
所以是的,它可能会产生“可能”错误的代码。
答案 2 :(得分:11)
您可以使用以下代码投射数据:
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);
答案 3 :(得分:5)
你有没有看过this answer?
严格的别名规则使这个 设置非法,两个不相关的类型 不能指向同一个记忆。的只有 char *拥有此权限。 不幸的是你仍然可以编码 方式,也许得到一些警告,但有 它编译得很好。
答案 4 :(得分:2)
严格别名是一个编译器选项,因此您需要将其从makefile中关闭。
是的,它可能会生成错误的代码。编译器将有效地假设foobar
和pi
未绑定在一起,并假设*pi
在foobar
更改时不会更改。
如前所述,请改用static_cast
(而不是指针)。