簡體   English   中英

g++ 嚴格溢出、優化和警告

[英]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工作原理。

關於有這種溢出的一些補充:

  1. 您可以使用#pragma GCC ...關閉這些警告#pragma GCC ...

    如果您確定您的代碼將始終有效(在您的函數中包裝整數很好),那么您可以在攻擊性塊或函數周圍使用編譯指示:

     #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-overflow" ...offensive code here... #pragma GCC diagnostic pop

    當然,這意味着您完全忽略錯誤並讓編譯器進行優化。 最好進行一個測試,使邊緣案例 100% 按預期工作!

  2. 關閉實際優化

    我更喜歡這個。 我遇到了今天在發布模式下會失敗的測試。 我在常規基礎上沒有使用任何東西,只有一個非常具體的邊緣情況,但它在Debug 中工作得很好,因此,不讓編譯器優化該功能是更好的選擇。 你實際上可以這樣做:

     T __attribute__((optimize("-fno-strict-overflow"))) func(...) { ... }

    該屬性通過按預期實際發出的代碼取消-fstrict-overflow ¹ 錯誤。 我的測試現在通過DebugRelease

注意:這是 g++ 特定的。 如果可用,請參閱您的編譯器文檔以獲取等效項。

無論哪種方式,正如上面 Frax 所提到的,在-O3模式下,編譯器希望通過刪除它和整個代碼塊來優化測試。 可以刪除整個塊,因為如果它是負數,則在r = -r;之后r = -r; ,那么r應該是正的。 所以再次測試負數被優化了,這就是編譯器警告我們的。 但是,使用-fstrict-overflow屬性,您可以要求編譯器在該函數中進行優化。 因此,您在所有情況下都會得到預期的行為,包括溢出。

¹我發現該選項名稱令人困惑。 在這種情況下,如果您使用-fstrict-overflow ,即使結果不遵守嚴格溢出,您-fstrict-overflow要求優化器進行優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM