簡體   English   中英

對於看似無關的變量,g ++“warning:iteration ...調用未定義的行為”

[英]g++ “warning: iteration … invokes undefined behavior” for Seemingly Unrelated Variable

請考慮strange.cpp的以下代碼:

#include <vector> 


using namespace std;


int i = 0;


int *bar()
{   
    ++i;
    return &i; 
}   


int main()
{   
    for(size_t j = 0; j < 99999999999; ++j) // (*)
    {   
        const auto p = bar();
        if(!p) // (**)
            return -1; 
    }   
}   

用g ++編譯它會發出警告:

$ g++ --std=c++11 -O3 strange.cpp 
strange.cpp: In function ‘int main()’:
strange.cpp:12:12: warning: iteration 4294967296ul invokes undefined behavior [-Waggressive-loop-optimizations]
         ++i;
            ^
strange.cpp:19:9: note: containing loop
         for(size_t j = 0; j < 99999999999; ++j) // (*)
         ^

我不明白為什么增量會調用未定義的行為。 此外,有兩個更改,每個更改使警告消失:

  1. 將行(*)更改for(int j...
  2. 將行(**)更改為if(!*p)

這個警告的含義是什么,為什么這些變化與之相關?

注意

$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4

增量是未定義的,因為一旦i到達std::numeric_limits<int>::max() (在32位,LP64或LLP64平台上為2 31 - 1),遞增它將溢出,這是有符號整數類型的未定義行為。

gcc在迭代4294967296ul(2 32 )而不是迭代2147483646u(2 31 )上發出警告,因為它不知道i的初始值 ; 其他一些代碼可能在main之前運行,將i設置為0以外的其他代碼。 但是一旦輸入main ,就沒有其他代碼可以運行來改變i ,因此一旦完成2 32次迭代,它將在某個時刻達到2 31 - 1並溢出。

  1. 通過將循環的控制條件轉換為同義的真實表達來“修復”它; 這使得循環成為一個無限循環,因為循環中的if將永遠不會執行,因為&i不能是空指針。 無限循環可以被優化掉 ,因此gcc消除了循環體,並且不會發生i的整數溢出。

  2. 通過允許gcc從整數溢出的未定義行為中取出來“修復”它。 防止整數溢出的唯一方法是使i的初始值為負,這樣在某些時候i達到零。 這是可能的(見上文),唯一的選擇是未定義的行為,所以它必須發生。 所以i達到零,循環內的if執行, main返回-1

暫無
暫無

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

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