2013-04-09 38 views
1

如果有一個函數沒有將任何引用或指針作爲參數,它的返回類型是未使用的,並且它沒有任何可觀察地離開系統的調用(I/O調用,更改系統時間等等),是否保證只修改它定義的類(或者什麼都不)?編譯器或定義的行爲可能的優化

,我能想到的此規則的唯一例外是類似如下:

void a(int b, int c){ 
    *((int*)b) = c; } 

int main() { 
    int d=1; 
    a((int)(&d),d+1); 
    return 0; } 

是保證界定?我知道int*int不必是相同的大小,但如果他們被定義爲相同的大小,這是否必須工作,或者它仍然是未定義的行爲?

目標是查看功能是否可以合法優化(即如果您可以證明它沒有副作用,可以將其刪除)。

+2

請參閱:[維基百科的死代碼消除](http://en.wikipedia.org/wiki/Dead_code_elimination)和[SO的死代碼](http://stackoverflow.com/questions/4813947/how-can-i -know-其中零件-內式代碼被-從未使用)。 – 2013-04-10 00:03:36

+0

@artlessnoise這是更多關於像http://stackoverflow.com/questions/15825188/removing-useless-lines-from-c-file。此外,這不是死代碼,這是沒有任何作用的實時代碼。 – soandos 2013-04-10 00:08:33

+0

不,我認爲(糾正我,如果我錯了),你不能優化它。考慮一下b和c是具有共享指針的類的實例,這些指針可能會受到影響。甚至考慮一下在離開示波器時發生的析構函數的調用。 – rralf 2013-04-10 00:11:18

回答

1

的標準保證reinterpret_cast用於從一個指針轉換爲適合整數類型(大到足以容納所有的值),並回原始指針類型保證產生相同的指針值。所以,是的,這是保證:

int *p = new int(5); 
intptr_t i = reinterpret_cast<intptr_t>(p); 
// ... 
int *q = reinterpret_cast<int*>(i); 

assert(p == q); 
*q = 10; 
assert(*p == 5); 

編譯器允許刪除沒有副作用的代碼,但不能清楚地僅檢查函數簽名確定。對於內聯函數,編譯器可以看到代碼,編譯器有機會。對於在不同翻譯單元中定義的函數,事情有點困難(使用鏈接時間優化,如果函數是足夠小,仍然可行)。

請注意,這不僅限於通過值或const引用接受參數的函數。如果編譯器通過引用看到一個函數修改了參數,但它可以證明修改的對象的值永遠不會再被讀取,它理論上可以刪除該調用。另一方面,除了簡單的情況之外,我不打賭編譯器會這樣做。

0

我想說這屬於「明確的未定義行爲」領域;它會大概一直工作(假設sizeof(int *)== sizeof(int)),但它在技術上是未定義的,並且有一個真正的機會,一些編譯器將來可能完全打破它。另一個例子是使用一個聯合來重新解釋一個float的位爲int。另外,如果我沒有把你指向LLVM的鏈接時間優化的方向,我會完全不對勁。它的目標是在鏈接時刻完成你正在談論的內容。這真棒,並在osx上「開箱即用」。他們還得到了它是如何工作的偉大,簡單的例子:http://llvm.org/docs/LinkTimeOptimization.html