天天看点

MySQL编译选项 -fno-strict-aliasing随手记

allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. for c (and c++), this activates optimizations based on the type of expressions. in particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. for example, an unsigned int can alias an int, but not a void* or a double. a character type may alias any other type.

当使用strict aliasing时, 编译器会认为在不同类型之间的转换不会发生,因此执行更激进的编译优化,例如reorder执行顺序。

strcit aliasing只能隐式的开启或者显式的禁止掉。在-o2或更高的编译级别上会被隐式开启。

函数的功能很简单,对一个数字的高低位进行交换

gcc版本

执行strict aliasing (o2及以上默认打开)

非strict aliasing (显式指定-fno-strict-aliasing)

不同的gcc flag,两次的执行结果居然完全不相同,只有第二次才实现了预期功能。因为默认情况下不报warning,我们把告警打开看看:

果然在使用strict aliasing时,因为破坏了严格aliasing的规则大量报警,因此如果我们要使用strict aliasing,一定要打开报警,并重视每个warning。

回到刚才的问题,为什么strict aliasing会输出最原始的数据,而不是修改后的数据呢 ? 看起来就好像后面的修改全部被忽略掉了一样。 我们来看看编译后的代码。可以看到两个汇编代码完全不相同。编译器认为代码里不可能出现不规范的类型转换,所以在错误的案例里,a的未被修改的值被直接抛给了printf函数

正确的 (gcc -o2 -fno-strict-aliasing x.c)

错误的 (gcc -o2 -fstrict-aliasing x.c)

但是如果我换成高版本的gcc,例如4.8版本,两种编译方式都没有问题,甚至加上-wstrict-aliasing连报警都没有。只有加上-wstrict-aliasing=1才报warning

!!!无论如何, 如果你需要打开strict aliasing, 一定要打开wstrict-aliasing,消除代码warning。 同时在代码上也要尽量减少这种不同类型的转换。

在mysql移除-fno-strict-aliasing后, 也看到了一些担忧,因为mysql的codebase毕竟已经相当古老了, 而当前并没有一些静态或动态的分析工具能够找到所有违反strict aliasing规则的地方。可能存在潜在的风险。

继续阅读