[英]g++ strict overflow, optimization, and warnings
使用嚴格溢出標志編譯以下內容時,它告訴我,在第二次測試中, r 可能不是我認為的那樣:
int32_t r(my_rand());
if(r < 0) {
r = -r;
if(r < 0) { // <-- error on this line
r = 0;
}
}
錯誤是:
/build/buildd/libqtcassandra-0.5.5/tests/cassandra_value.cpp:
In function 'int main(int, char**)':
/build/buildd/libqtcassandra-0.5.5/tests/cassandra_value.cpp:2341:13:
error: assuming signed overflow does not occur when simplifying
conditional to constant [-Werror=strict-overflow]
if(r < 0) {
^
我不明白的是:為什么在此之前不會在行上生成錯誤? 因為當我這樣做時確實會發生溢出,對嗎?
r = -r;
編輯:我刪除了我的第一個答案,因為它無效。 這是全新的版本。 感謝@Neil Kirk指出我的錯誤。
這個問題的答案在這里: https : //stackoverflow.com/a/18521660/2468549
GCC總是假設,簽名溢出永遠不會發生,並且在該假設下,它(總是)優化內部if (r < 0)
塊。
如果你打開-Wstrict-overflow
,那么編譯器會發現,在r = -r
r < 0
仍然可能為真(如果r == -2^31
最初),這會導致錯誤(錯誤是由基於優化引起的假設溢出永遠不會發生,而不是溢出可能性本身 - 這就是-Wstrict-overflow
工作原理。
關於有這種溢出的一些補充:
您可以使用#pragma GCC ...
關閉這些警告#pragma GCC ...
如果您確定您的代碼將始終有效(在您的函數中包裝整數很好),那么您可以在攻擊性塊或函數周圍使用編譯指示:
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-overflow" ...offensive code here... #pragma GCC diagnostic pop
當然,這意味着您完全忽略錯誤並讓編譯器進行優化。 最好進行一個測試,使邊緣案例 100% 按預期工作!
關閉實際優化
我更喜歡這個。 我遇到了今天在發布模式下會失敗的測試。 我在常規基礎上沒有使用任何東西,只有一個非常具體的邊緣情況,但它在Debug 中工作得很好,因此,不讓編譯器優化該功能是更好的選擇。 你實際上可以這樣做:
T __attribute__((optimize("-fno-strict-overflow"))) func(...) { ... }
該屬性通過按預期實際發出的代碼取消-fstrict-overflow
¹ 錯誤。 我的測試現在通過Debug和Release 。
注意:這是 g++ 特定的。 如果可用,請參閱您的編譯器文檔以獲取等效項。
無論哪種方式,正如上面 Frax 所提到的,在-O3
模式下,編譯器希望通過刪除它和整個代碼塊來優化測試。 可以刪除整個塊,因為如果它是負數,則在r = -r;
之后r = -r;
,那么r
應該是正的。 所以再次測試負數被優化了,這就是編譯器警告我們的。 但是,使用-fstrict-overflow
屬性,您可以要求編譯器在該函數中進行優化。 因此,您在所有情況下都會得到預期的行為,包括溢出。
¹我發現該選項名稱令人困惑。 在這種情況下,如果您使用-fstrict-overflow
,即使結果不遵守嚴格溢出,您-fstrict-overflow
要求優化器進行優化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.