g++ "warning: iteration ... invokes undefined behavior" 表示看似无关的变量
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) // (*)
^
我不明白为什么增量会调用未定义的行为。此外,还有两个变化,每个变化都使警告消失:
- 将行
(*)
更改为 for(int j...
- 将行
(**)
更改为 if(!*p)
此警告的含义是什么,为什么要进行相关更改?
备注
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
增量未定义,因为一旦 i
达到 std::numeric_limits<int>::max()
(在 32 位、LP64 或 LLP64 平台上为 231 - 1),递增它会溢出,这是有符号整数类型的未定义行为。
gcc 在迭代 4294967296ul (232) 而不是迭代 2147483646u (231) 上发出警告,如您所料,因为它不知道i
的初始值;一些其他代码可能在 main
之前有 运行 以将 i
设置为 0
以外的其他内容。但是一旦输入 main
,没有其他代码可以 运行 改变 i
,因此一旦 232 迭代完成,它将在某个时刻达到 231 - 1 溢出。
"fixes" 把循环的控制条件变成同义反复的真表达式;这使得循环成为无限循环,因为循环内的 if
永远不会执行,因为 &i
不能是空指针。 Infinite loops can be optimized away,所以gcc去掉了循环体,不会出现i
的整数溢出。
"fixes" 它通过允许 gcc 摆脱未定义的整数溢出行为。防止整数溢出的唯一方法是 i
有一个负的初始值,这样在某个时候 i
达到零。这是可能的(见上文),唯一的选择是未定义的行为,所以它 必须 发生。所以i
归零,循环里面的if
执行,main
returns-1
.
考虑 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) // (*)
^
我不明白为什么增量会调用未定义的行为。此外,还有两个变化,每个变化都使警告消失:
- 将行
(*)
更改为for(int j...
- 将行
(**)
更改为if(!*p)
此警告的含义是什么,为什么要进行相关更改?
备注
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
增量未定义,因为一旦 i
达到 std::numeric_limits<int>::max()
(在 32 位、LP64 或 LLP64 平台上为 231 - 1),递增它会溢出,这是有符号整数类型的未定义行为。
gcc 在迭代 4294967296ul (232) 而不是迭代 2147483646u (231) 上发出警告,如您所料,因为它不知道i
的初始值;一些其他代码可能在 main
之前有 运行 以将 i
设置为 0
以外的其他内容。但是一旦输入 main
,没有其他代码可以 运行 改变 i
,因此一旦 232 迭代完成,它将在某个时刻达到 231 - 1 溢出。
"fixes" 把循环的控制条件变成同义反复的真表达式;这使得循环成为无限循环,因为循环内的
if
永远不会执行,因为&i
不能是空指针。 Infinite loops can be optimized away,所以gcc去掉了循环体,不会出现i
的整数溢出。"fixes" 它通过允许 gcc 摆脱未定义的整数溢出行为。防止整数溢出的唯一方法是
i
有一个负的初始值,这样在某个时候i
达到零。这是可能的(见上文),唯一的选择是未定义的行为,所以它 必须 发生。所以i
归零,循环里面的if
执行,main
returns-1
.