日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

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

系統(tǒng) 2672 0

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

事情是這樣的。我們對tair(淘寶的分布式Key/Value系統(tǒng))動了一次大手術(shù),更換了網(wǎng)絡(luò)框架,經(jīng)過長時間的測試/調(diào)試,終于完全通過了回歸測試。但要打包發(fā)布的時候,卻發(fā)現(xiàn)服務(wù)器可以正常啟動,但卻完全無法接受請求。調(diào)試無果,對比打包前后程序的差異,僅在于是否使用-O2選項對程序進行編譯優(yōu)化。
無頭蒼蠅一樣,Google搜索“gcc optimization problems”,找到StackOverflow上面的 這個帖子 ,“抱著試試看的心態(tài)”,在編譯選項中加入-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規(guī)則下,C/C++編譯器認為,“不同類型”的指針(準確說是lvalue)一定不會引用同一個內(nèi)存區(qū)域(即aliasing)。在這個規(guī)則的前提下,編譯器就可以進行相應(yīng)的優(yōu)化。看下面這個函數(shù):

                  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
                  
                

一切正常,不是嗎?但如果把函數(shù)foo的參數(shù)類型改作double*,運行結(jié)果“可能”會是:

                  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沒有被執(zhí)行嗎?不是的,*ptr=3確實是執(zhí)行了的,全局變量n在函數(shù)返回時也確實已經(jīng)是3了(你可以在fprintf之后打印出n值做驗證),但是foo函數(shù)中的語句return n卻被優(yōu)化成了return 1。為什么呢?因為后者比前者稍了一次內(nèi)存訪問。編譯器為什么做這樣的優(yōu)化,為什么在ptr為int*時不做此優(yōu)化?
這就涉及到strict aliasing的具體規(guī)則了。首先定義一下alias:兩個不同的變量引用了同一個對象(內(nèi)存區(qū)域),那么就稱這兩個變量互為alias。下面是C99中可以互為alias的所有情況,除此之外的其他情況下,如果編譯時指定-fstrict-aliasing(-O2及以上優(yōu)化時自動指定),那么就執(zhí)行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規(guī)則,同時也就放棄了這個規(guī)則帶來的優(yōu)化空間,放棄了一定的性能提升。如果你也遇到了文章開頭我遇到的問題,而且擔心-fno-strict-aliasing的性能損失,那就只能找出違反規(guī)則的代碼,調(diào)整該代碼,或者僅僅取消該代碼的strict aliasing。

基本就是這樣了,最后總結(jié)一下。GCC的aliasing與優(yōu)化緊密相關(guān),在指定-O2及以上優(yōu)化級別時自動打開-fstrict-aliasing,執(zhí)行strict aliasing規(guī)則以優(yōu)化編譯程序。如果你的程序不遵守該規(guī)則(比如上面foo函數(shù)中出現(xiàn)double*ptr和n同時應(yīng)用n的情況),就極有可能受到懲罰。GCC中與strict aliasing相關(guān)的選項除了-fstrict-aliasing/-fno-strict-aliasing,還有warning選項-Wstrict-aliasing=n,這個選項在你違反stict aliasing時給出警告,其中n為檢查的力度,一般設(shè)為2。

最后,如果想深入了解strict aliasing,可以參考這篇 Understanding Strict Aliasing 。另外,GCC的官方文檔中有和 優(yōu)化選項相關(guān)的描述 ,其中也提到了strict aliasing。

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 交口县| 洛宁县| 科尔| 娱乐| 犍为县| 日照市| 大兴区| 北流市| 藁城市| 拜泉县| 衡水市| 临桂县| 香格里拉县| 富裕县| 阿尔山市| 穆棱市| 眉山市| 海口市| 康平县| 东源县| 武乡县| 靖宇县| 南康市| 二连浩特市| 安仁县| 全椒县| 盐山县| 兴化市| 日照市| 贵定县| 思茅市| 河间市| 门源| 灌云县| 沙坪坝区| 康定县| 伊宁市| 卢湾区| 环江| 嵩明县| 樟树市|