首页IT科技嫉妒是一个人对另一个人发自内心的认可(GCC strict aliasing – 嫉妒就是承认自己不如别人)

嫉妒是一个人对另一个人发自内心的认可(GCC strict aliasing – 嫉妒就是承认自己不如别人)

时间2025-05-02 01:08:13分类IT科技浏览3581
导读:事情是这样的。我们对tair(淘宝的分布式Key/Value系统)动了一次大手术,更换了网络框架,经过长时间的测试/调试,终于完全通过了回归测试。但要打包发布的时候,却发现服务器可以正常启动,但却完全无法接受请求。调试无果,对比打包前后程序的差异,仅在于是否使用-O2选项对程序进行编译优化。...

事情是这样的        。我们对tair(淘宝的分布式Key/Value系统)动了一次大手术            ,更换了网络框架              ,经过长时间的测试/调试     ,终于完全通过了回归测试                 。但要打包发布的时候         ,却发现服务器可以正常启动               ,但却完全无法接受请求      。调试无果       ,对比打包前后程序的差异      ,仅在于是否使用-O2选项对程序进行编译优化      。

无头苍蝇一样                ,Google搜索“gcc optimization problems            ”         ,找到StackOverflow上面的这个帖子   ,“抱着试试看的心态              ”                 ,在编译选项中加入-fno-strict-aliasing           ,bingo!

-fno-strict-aliasing这个选项是做什么的?aliasing又是什么?C和C++的标准给出了说明: Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias eachother.)

即是说,在strict aliasing规则下               ,C/C++编译器认为              ,“不同类型     ”的指针(准确说是lvalue)一定不会引用同一个内存区域(即aliasing)                。在这个规则的前提下   ,编译器就可以进行相应的优化         。看下面这个函数:

1 2 3 4 5 6 7 8 9 10 int n; int foo(int *ptr) { n=1; *ptr=3; return n; } int main() { fprintf(stdout, "%d\n", foo(&n)); return 0; }

编译并运行:

1 2 3 4 $ cc main.c && ./a.out 3 $ cc main.c -O2 && ./a.out 3

一切正常            ,不是吗?但如果把函数foo的参数类型改作double*              ,运行结果“可能         ”会是:

1 2 3 4 5 6 $ cc main.c && ./a.out 3 $ cc main.c -O2 && ./a.out 1 $ cc main.c -O2 -fno-strict-aliasing && ./a.out 3

在加-O2选项的情况下程序编译该程序     ,输出竟然是1         ,难道*ptr=3没有被执行吗?不是的               ,*ptr=3确实是执行了的       ,全局变量n在函数返回时也确实已经是3了(你可以在fprintf之后打印出n值做验证)      ,但是foo函数中的语句return n却被优化成了return 1    。为什么呢?因为后者比前者稍了一次内存访问               。编译器为什么做这样的优化                ,为什么在ptr为int*时不做此优化?

这就涉及到strict aliasing的具体规则了            。首先定义一下alias:两个不同的变量引用了同一个对象(内存区域)         ,那么就称这两个变量互为alias  。下面是C99中可以互为alias的所有情况   ,除此之外的其他情况下                 ,如果编译时指定-fstrict-aliasing(-O2及以上优化时自动指定)           ,那么就执行strict aliasing: a type compatible with the effective type of the object, a qualified version of a type compatible with the effective type of the object, a type that is the signed or unsigned type corresponding to the effective type of the object, a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object, an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), a character type.

大致是这样的:两个类型兼容的变量可以互为alias,即使使用了signed/unsigned和const/volatile等修饰符;一个类型可以与另一个包含与该类型兼容的成员的struct/union类型的变量互为alias;char类型可以与任意类型互为alias              。C++中可以互为alias的还可以是父类与子类               。

可以使用-fno-strict-aliasing来取消strict aliasing规则               ,同时也就放弃了这个规则带来的优化空间              ,放弃了一定的性能提升。如果你也遇到了文章开头我遇到的问题   ,而且担心-fno-strict-aliasing的性能损失            ,那就只能找出违反规则的代码              ,调整该代码     ,或者仅仅取消该代码的strict aliasing           。

基本就是这样了         ,最后总结一下                  。GCC的aliasing与优化紧密相关               ,在指定-O2及以上优化级别时自动打开-fstrict-aliasing       ,执行strict aliasing规则以优化编译程序   。如果你的程序不遵守该规则(比如上面foo函数中出现double*ptr和n同时应用n的情况)      ,就极有可能受到惩罚        。GCC中与strict aliasing相关的选项除了-fstrict-aliasing/-fno-strict-aliasing                ,还有warning选项-Wstrict-aliasing=n         ,这个选项在你违反stict aliasing时给出警告   ,其中n为检查的力度                 ,一般设为2                 。

最后           ,如果想深入了解strict aliasing,可以参考这篇Understanding Strict Aliasing      。另外               ,GCC的官方文档中有和优化选项相关的描述              ,其中也提到了strict aliasing      。

声明:本站所有文章   ,如无特殊说明或标注            ,均为本站原创发布                。任何个人或组织              ,在未征得本站同意时     ,禁止复制            、盗用              、采集     、发布本站内容到任何网站         、书籍等各类媒体平台         。如若本站内容侵犯了原著者的合法权益         ,可联系我们进行处理    。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
yolov3目标检测实战(YOLOv7(目标检测)入门教程详解—检测,推理,训练) 网页抓取原理及技术(网页抓取数据-抓取网页数据的几种方式)