从一个返回值类型不为 void 的函数返回,但是却没有指定返回值,是 undefined behavior。

C/C++ 编译器可以利用 undefined behavior 执行非常激进的优化。例如,有一个优化策略是,编译器可以假定程序中任意一条路径中没有任何的 undefined behavior。在本例中,参考这个策略,编译器会认为 test 函数中的 for 循环永不退出(因为只要退出,就会产生 UB)。因此,编译器在高优化级别下可能将 test 中的循环直接优化为一个死循环。

作者:WhoTFAmI
链接:https://www.zhihu.com/question/472017255/answer/2328368097
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

大家都知道和未定义行为(UB,Undefined Behavior)有关,但不是“编译器认为这个循环是死循环”。maxn是一个常量对象(const object),值是不会被改变的,循环次数不会超过 maxn,所以编译器不能认为它是一个可以循环无限次的死循环。

那为什么编译器优化成”死循环“了呢?

因为在C++中,有返回值的函数在执行到尾部时若没有 return 是UB,编译器从“程序不存在UB”的假设出发,可以推断该函数不会返回,从代码控制流中可以知道,唯一的“出口”是 printf 函数,于是推断出循环条件成立范围内,有一次调用 printf 函数后它将不返回(printf 内有死循环或者终止程序),此前循环条件总是成立,此后再也不会回到这个循环,所以循环条件被优化掉了。

实际运行时,printf并没有如推断中那样死循环或者终止程序,所以当 i 超过 maxn 之后是 UB 的其中一种体现。

注:以上假设问题代码是C++,因为在C++中是UB,在C中如果未使用返回值则不是UB,根据题目的描述已经产生了UB,未搜索到GCC的相关历史BUG,认为题主使用的是C++。

补充:为以上与 printf 有关的说法增加一些说服力

f2 没有调用外部函数,在所有控制流中都有 UB,编译器会推断该函数根本不会被调用(否则就会有UB),因此不为 f2 输出任何指令。可以说明编译不是简单地认为是死循环。

06-13 00:44