无限循环与无限递归。都不确定吗?

时间:2019-04-17 19:23:05

标签: c++ loops recursion language-lawyer undefined-behavior

没有副作用的无限循环是不确定的行为。有关here中的示例,请参见cppreference。更简单的例子:

int foo() {
    while(true) {}
    return 42;
}

现在考虑几乎等同的

int bar() {
    if (true) return bar();
    return 42;
}

这还会调用未定义的行为吗?

或用不同的措辞表达:根据语言,无限递归属于哪类错误?

PS:请注意,我知道运行时的含义:循环原则上可以永远运行,而递归最终将导致stackoverflow。尽管我主要对编译器对它们的操作感兴趣。也许是一个相当学术性的问题...

2 个答案:

答案 0 :(得分:10)

不,没有区别。 [basic.progress]p1

  

该实现可以假定任何线程最终都会执行以下操作之一:

     
      
  • 终止,

  •   
  • 调用库I / O函数,

  •   
  • 通过易失的glvalue执行访问,或

  •   
  • 执行同步操作或原子操作。

  •   

无限循环的方式无关紧要;如果它没有完成以上任何要点,您将获得UB。包括以下内容:

int bar(int cond) {
    if (cond == 42) bar(cond);
    return 42;
}
bar(some_user_input);

允许编译器假定some_user_input永远不会是42。

答案 1 :(得分:0)

在大多数现实世界中,邀请某人假设会发生某事意味着它没有义务采取任何特殊措施来避免发生这种情况,但是如果发生以下情况,它就不是一种以任意方式行事的许可证人们发现有关事件不会发生。

但是,在对C标准的时髦解释下,如果该标准邀请他们做出的任何假设是不正确的,则没有理由期望实现会避免完全荒谬的方式。

我不认为该标准的作者打算让C编译器使用复杂的推理引擎,这些引擎将假设级联到编译器给出的例如

的地步。
if (x > 1000) foo(x);
while ( x <= 1000)
  somethingWithNoSideEffectsThatCantAffectX();

将得出结论,无论foo的值如何,都应无条件执行x。他们更有可能希望编译器给出类似以下内容:

volatile int yy;
void test(int x, int *restrict arr)
{
  int y;
  do
    x=arr[x];
  while(x & 1);
  y=yy;
  if (y)
    printf("%d\n",x);
}

将被允许使用这样的事实:在x的最终值不存在的情况下,可以{或不需要} getElementById的最终值来重新排列代码(通过完全跳过其计算)以提高效率。本质上,一段代码要花时间来执行-即使无限,它们也不应被视为副作用,并且如果编译器可以证明一段代码可以代码无法在到达某个位置之前执行任何可见的副作用,因此无需在该位置执行代码之前就等待该代码段完成。

不幸的是,该标准的作者依靠编译器作者根据某些假设来认识到可以采取何种有效的措施,而编译器作者则认为应该推断出他们可以得出的任何可能推论。