2013-04-23 65 views
1

改變這裏有一個簡單的代碼告訴GCC優化該值在全局函數

void GlobalAlterA(A *a) { a->m = 1; } 
struct A { int n, int m; }; 
struct Z: public A { void AlterA() { GlobalAlterA(this); } }; 
struct Y: public Z {}; 
struct X: public Y 
{ 
    int AsValue() 
    { 
     switch (n) 
     { 
      case 0: return m; 
      default: AlterA(); return m; 
     } 
    } 
}; 

現在,有了這個代碼的問題是GCC優化扔掉所有AsValue()的代碼,除了「迴歸M」,因爲,我想,它沒有看到GlobalAlterA()主體,也不知道AlterA()可以更改「m」成員。

有沒有辦法解決這個問題,除了關閉特定部分代碼的優化?例如。像易失性說明符等技巧。

+0

您使用的是哪個版本的gcc?在修改代碼以便編譯之後,它會生成我期望的值(「沒有顯式優化」和「-O3」)。也許你可以向我們展示如何使用上面的代碼。 – 2013-04-23 14:19:03

+2

您能否發佈完整的問題演示?如果編譯器影響程序的行爲,編譯器當然不應該刪除對「AlterA」的調用。 – 2013-04-23 14:19:29

+3

我剛剛用-O3編譯了這個,使用gcc 4.7.2彙編語言,並在x86_64上查看它,它看起來不像你說的那樣。我在開始時添加了代碼「std :: cin >> x.n >> x.m」來設置n和m的值,並且修正了一些編譯的東西,比如在定義之前使用類型A,並且根本不能重現。 – jcoder 2013-04-23 14:20:00

回答

2

這已經被優化器假定了,所以你不能讓它假設它已經假設的東西。

不過,如果你認爲你改變的值,但實際上均創下未定義行爲(例如,因爲您修改m通過一個類型punned指針,或union濫用),則優化完全在其假設m的權利沒有改變。最好的解決方法當然是移除該UB,或者(至少這樣做)至少將其從優化器中隱藏起來。

+0

當GlobalAlterA位於單獨的共享庫中時,優化器是否知道並假定GlobalAlterA會做什麼(帶有或不帶有UB)? – queen3 2013-04-23 15:23:39

+2

@ queen3:它必須假設'GlobalAlterA'改變了所有可以在沒有UB的情況下被改變的變量,並且它可以假設它只改變那些變量。更短:優化器可能不承擔UB。衆所周知的例子:給定'int i','i + 1> 1'可能被假定爲真。溢出是UB,所以'INT_MAX + 1> INT_MAX == true'是一個有效的優化。 – MSalters 2013-04-23 15:29:38

+0

試圖欺騙編譯器在面對UB時以特定的方式行爲將會一次又一次地燒燬你。在這種情況下,你可能會欺騙這個版本的編譯器來「做你想做的事」,但是每次你升級編譯器,或者改變任何使用它的代碼時,它會再次陷入另一個細微的錯誤中。您必須將UB轉換爲定義的行爲。你的「複雜的嵌套結構/聯合的東西」幾乎肯定需要去複雜化。 – 2013-04-23 15:44:27