g ++“warning:iteration ...调用未定义的行为”看似无关的变量 [英] g++ "warning: iteration ... invokes undefined behavior" for Seemingly Unrelated Variable

查看:1558
本文介绍了g ++“warning:iteration ...调用未定义的行为”看似无关的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码 strange.cpp

 #包括< vector> 


使用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;


$ / code>

用g ++编译会给出警告:

  $ g ++ --std = c ++ 11 -O3 strange.cpp 
strange.cpp:In function'int main( )':
strange.cpp:12:12:warning:迭代4294967296ul调用未定义的行为[-Waggressive-loop-optimizations]
++ i;
^
strange.cpp:19:9:注意:包含循环
for(size_t j = 0; j< 99999999999; ++ j)//(*)
^

我不明白为什么增量会调用未定义的行为。此外,还有两个更改,每个都会使警告消失:
$ b


  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() code> (32位,LP64或LLP64平台上的2 31 - 1),将其递增,这对于带符号的整型类型是未定义的行为。 >

gcc在迭代4294967296ul(2 32 )时发出警告而不是迭代2147483646u(2 31 ),因为它不知道 i 的初始值;一些其他的代码可能在 main 之前运行,以将 i 设置为 0以外的其他代码。 code>。但是一旦输入 main ,没有其他代码可以运行来修改 i ,所以一次2 32 迭代已经完成,它将在某一时刻达到2 31 - 1并溢出。


  1. <通过将循环的控制条件变成同义反复的真实表达式来修复它;因为& i 不能成为循环内的 if一个空指针。 无限循环可以被优化,所以gcc消除了循环和 i 的整数溢出不会发生。
  2. 通过允许gcc和从整数溢出的未定义的行为。防止整数溢出的唯一方法是使 i 的初始值为负值,这样在某点 i 达到零。这是可能的(见上文),唯一的选择是未定义的行为,所以它必须发生。因此 i 达到零,循环内的 if if 会执行,并且 main 返回 -1



Consider the following code in 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; 
    }   
}   

Compiling this with g++ gives a warning:

$ 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) // (*)
         ^

I don't understand why the increment invokes undefined behavior. Moreover, there are two changes, each of which makes the warning disappear:

  1. changing the line (*) to for(int j...
  2. changing the line (**) to if(!*p)

What is the meaning of this warning, and why are the changes relevant to it?

Note

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

解决方案

The increment is undefined because once i reaches std::numeric_limits<int>::max() (231 - 1 on a 32-bit, LP64 or LLP64 platform), incrementing it will overflow, which is undefined behavior for signed integral types.

gcc is warning on iteration 4294967296ul (232) rather than iteration 2147483646u (231) as you might expect, because it doesn't know the initial value of i; some other code might have run before main to set i to something other than 0. But once main is entered, no other code can run to alter i, and so once 232 iterations have completed it will have at some point reached 231 - 1 and overflowed.

  1. "fixes" it by turning the controlling condition of the loop into a tautologically true expression; this makes the loop an infinite loop, since the if inside the loop will never execute, as &i cannot be a null pointer. Infinite loops can be optimized away, so gcc eliminates the body of the loop and the integer overflow of i does not occur.

  2. "fixes" it by allowing gcc an out from the undefined behavior of integer overflow. The only way to prevent integer overflow is for i to have an initial value that is negative, such that at some point i reaches zero. This is possible (see above), and the only alternative is undefined behavior, so it must happen. So i reaches zero, the if inside the loop executes, and main returns -1.

这篇关于g ++“warning:iteration ...调用未定义的行为”看似无关的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆