欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

GCC strict aliasing – 嫉妒就是承認自己不如

系統 2366 0

GCC strict aliasing – 嫉妒就是承認自己不如別人

事情是這樣的。我們對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。

GCC strict aliasing – 嫉妒就是承認自己不如別人


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!??!

主站蜘蛛池模板: 亚洲精品国产电影 | 狼伊千合综网中文 | 亚洲欧美在线视频 | 国产网站视频 | 九一国产精品 | 国产视频中文字幕 | 免费黄色欧美视频 | 中文字幕三区 | avtom影院入口永久在线观看 | 日本人与黑人xxxx | 美女久久久久久久久久久 | 日本一区二区三区免费观看 | xx免费视频| 国产精品免费播放 | 一级黄色毛片视频 | 婷婷色九月综合激情丁香 | 超级碰碰碰视频在线观看 | 天天草天天干天天 | 色哟哟国产成人精品 | 高清一区二区在线观看 | 91久久精品国产 | 操操操操网 | 日本在线你懂的 | 精品国产欧美 | 福利一区在线视频 | 九九热视频在线观看 | 正在播放国产精品 | 日韩二区 | 欧美精品一区三区 | 一级性生活免费视频 | 麻豆一区二区99久久久久 | www国产成人免费观看视频,深夜成人网 | 亚洲一区视频 | www欧美视频| 亚洲综合欧美日韩 | 一级毛片ab片高清毛片 | 麻豆md国产在线观看 | 丝袜美腿视频一区二区三区 | 看真人视频a级毛片 | 欧美性生活久久 | 日韩欧美国产偷亚洲清高 |