2011-07-13 118 views
1

請看下面的例子:gcc的優化影響邊界檢查

int a[4]; 

int main() { 
    a[4] = 12; // <-- 
    return 0; 
} 

這顯然是一個出界失誤,是不是?我想知道gcc何時會對此提出警告,並發現只有在優化爲-O2或更高版本(這受-ftree-vrp選項影響,該選項僅自動設置爲-O2或更高版本)時纔會這樣做。 我真的不明白爲什麼這是有道理的,gcc是否是正確的,否則不會發出警告。

文檔具有這樣說事項:

這允許優化,以除去不必要的範圍檢查狀陣列結合檢查和空指針檢查。

不過,我不明白爲什麼檢查應該是不必要的?

+0

關注評論downvote? – bitmask

回答

1

你舉的例子是常數傳播,不值範圍傳播的情況下,它肯定會觸發我的版本的GCC(4.5.1)的警告-ftree-vrp是否被啓用。

一般來說,Java和Fortran語言是由GCC其唯一支持的語言(Java在默認情況下,和FORTAN如果你明確要求它-fbounds-check)將生成的代碼檢查數組邊界。

但是,雖然C/C++不支持任何這樣的事情,但編譯器仍然會在編譯時警告,如果它認爲有什麼不妥。對於常量來說,這對於變量範圍來說非常明顯,這有點難度。

子句「允許編譯器刪除不必要的範圍檢查」涉及例如使用無符號的8位寬變量來索引具有> 256個條目或無符號16位值的數組以索引到> 65536個元素的數組。或者,如果你在一個循環中迭代一個數組,並且(可變)循環計數器的值是,那麼這個值可以被證明爲合法數組索引的編譯時常量,所以計數器永遠不可能超出數組界限。
在這種情況下,編譯器將既不警告您也不生成目標語言的任何代碼,如果支持它。

+0

所以,如果你用'gcc -O0 -Wall main.c'編譯我的示例代碼,它('gcc 4.4.3')會引發你一個警告?因爲它肯定不在我的機器上。但是,如果我說'-O2'而不是'-O0',它確實如此。 – bitmask

+0

我用'-O2'和'-O3',用'-Wall'和without以及'-fbounds-check'和不用'編譯了它。每次都有一個警告(gcc 4.5.1)。 – Damon

+0

準確地說,正如我所說的,你總是會用'-O2' **和更高**(即'-O3'和'-Os')發出警告。然而,**你不會用'-O1'和'-O0'來**。原因在於'-ftree-vrp'由'-O2','-O3'和'-Os'隱含。問題是爲什麼? - 如果你可以再次嘗試一下,例如'-O0',那將會很棒。 – bitmask