strict aliasing

来源:互联网 发布:js与jsp的区别 编辑:程序博客网 时间:2024/05/21 14:03

转载于:http://www.cnblogs.com/vv1133/articles/2633669.html

zjs@xhacker:/tmp$ cat tt.c#include <stdio.h>int main(){     int a = 0x12345678;     short *p = (short *)&a;     short temp;     temp = *p;     *p = *(p+1);     *(p+1) = temp;     printf("%x\n", a);}zjs@xhacker:/tmp$ gcc   -O2   tt.czjs@xhacker:/tmp$ ./a.out 12345678zjs@xhacker:/tmp$ gcc -vUsing built-in specs.Target: i486-linux-gnuConfigured with: ../src/configure -v --with-pkgversion='Debian 4.3.1-2' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-cld --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnuThread model: posixgcc version 4.3.1 (Debian 4.3.1-2) 上面的指令把环境啥的都揭示的很清楚。这段代码主要是交换一个整数的前一个字和后一个字,结果很奇怪是不,竟然没交换:D,是不是我土了代码写错?好,再看zjs@xhacker:/tmp$ gcc tt.czjs@xhacker:/tmp$ ./a.out 56781234awesome!结果完全正确二。分析表面上立马看出结果不同的原因在于gcc编译时的参数不同,gcc -O2优化开启了很多优化选项,可以到gnu网站查的,其中有一项就是-fstrict-aliasing,这开启了aliasing规则1.那么什么是aliasing规则呢?先看gcc对-fstrict-aliasing的解释Allows the compiler to assume the strictest aliasing rulesapplicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. Inparticular, an object of one type is assumed never to reside at the sameaddress as an object of a different type, unless the types are almostthe same. For example, an unsigned int can alias an int, but not avoid* or a double. A character type may alias any other type.再看c99标准对aliasing的7 An object shall have its stored value accessed only by an lvalue    expression that has one of the following types: {footnote 73}      a type compatible with the effective type of the object,      a qualified version of a type compatible with the effective type ofthe object,      a type that is the signed or unsigned type corresponding to theeffective type of the object,      a type that is the signed or unsigned type corresponding to aqualified version of the effective type of the object,      an aggregate or union type that includes one of the aforementionedtypes among its members (including, recursively, a member of asubaggregate or contained union), or      a character type. {footnote 73} The intent of this list is to specify those circumstancesin which an object may or may not be aliased.gcc的说明更直白点,更容易懂。再看代码short *p = (short *)&a;该语句中p是指向short的指针,&a是指向int的指针,这破坏了aliasing规则。2.破坏aliasing规则为什么会出错呢?这要从c99为啥提了这么个东东说起,在我理解中,不同类型的指针一定不会指向同一个内存位置会有两个好处,1是减少可能的load和store;2是编译器可以对指令做些调整优化。出错就是因为开启了strict aliasing规则后,gcc认为*p不会指向&a所在的内存位置所以*p的操作和最后打印a没关系,指令可以reorder。实际上汇编结果表明正是如此gcc -O2 -S tt.c后tt.s部分内容:     movl     $305419896, 4(%esp) //可以看出直接送数据,根本不管*p的操作的     movl     $.LC0, (%esp)     call     printf3.c99的restrict关键字这个就不多说了。它起的作用是表明其修饰的指针不会被其它指针aliased扩展了strict aliasing4.对代码作者的影响对新写的代码,要确保不违反这个规则,那么确实需要让不同指针指向同一个内存位置怎么办?解决方案参考文献中写得很好,可以看看。当然有不少情形下不违反这个规则非常麻烦,比如os的内核等特殊地方,那么加入fno-strictaliasing参数,大家可以发现bsd内核、linux内核编译参数都加了这个对于已有的代码,违反的地方非常多,那么可以加gcc的-fno-strict-aliasing参数。三。问题发现过程我有时会把linux内核的部分代码用在应用层,linux内核编译时是加了-fno-strict-aliasing这个参数的(内核编译时加V=1可以看到)可应用的代码不一定,猜到是和内核的编译参数有关,最后没办法了,对于所有的参数看着谁像,就去google,最后找到的四。启发os内核的编译参数都是各个大牛呕心沥血精心挑选的,选这个参数有他们的用意,体会这种用意的同时,我们的水平也会提升。这让我想起曾经一款处理器平台,它的linux模块加载老是不成功,找来找去最后还是找到了编译参数。那是我第一次和编译参数做斗争:),现在看来和编译参数斗其乐无穷ps:代码实验必需确保你编译器支持c99标准,而同时有打开和关闭aliasing规则的参数开关,gcc3.X以后的就可以,微软的不清楚两个比较好的参考文献1.http://en.wikipedia.org/wiki/Aliasing_(computing) 2.http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html

0 0
原创粉丝点击