给定代码中的未定义行为?

时间:2015-09-30 06:44:42

标签: c++ c c++11 undefined-behavior unspecified-behavior

  

如果p的值为f,则f(p,p)的返回值是多少   在通话前初始化为5?请注意,第一个参数是   通过引用传递,而第二个参数按值传递。

int f (int &x, int c) {
       c = c - 1;
       if (c==0) return 1;
       x = x + 1;
       return f(x,c) * x;
}
     

选项包括:

     
      
  1. 3024
  2.   
  3. 6561
  4.   
  5. 55440
  6.   
  7. 161051
  8.   

我试着解释一下:

在此代码中,将有四个带参数(6,4),(7,3),(8,2)和(9,1)的递归调用。最后一次调用返回1.但是由于通过引用传递,所有先前函数中的x现在是9.因此,f(p,p)返回的值将是9 * 9 * 9 * 9 * 1 = 6561。 / p>

这个问题来自竞争性考试GATE,(see Q.no.-42)。答案的关键是GATE" Marks to all" (意味着没有选项正确。)key set-C, Q.no.-42。某处解释为:

在GATE 2013中,标记被赋予所有,因为C / C ++中的相同代码会产生未定义的行为。这是因为*不是C / C ++中的序列点。正确的代码必须替换

return f(x,c) * x;

 res = f(x,c);
 return res * x;

但是给定的代码工作正常。盖茨的关键是错的吗?或者问题确实是错误的?

2 个答案:

答案 0 :(得分:14)

   return f(x,c) * x;

此操作的结果取决于评估两件事的顺序。由于您无法预测它们的评估顺序,因此您无法预测此操作的结果。

答案 1 :(得分:9)

C ++ 03第5章:

  

除非另有说明,否则单个操作员的操作数和个体的子表达式的评估顺序   表达式以及副作用发生的顺序是未指定的。

因此,在f(x,c) * x的情况下,操作数的评估顺序未指定,这意味着您无法知道左或右操作数是否会首先被评估。

您的代码具有未指定的行为,这意味着它将以某种定义的方式运行,该方式仅为编译器所知。程序员不知道代码会做什么,只是它首先评估左操作数,或者先评估右操作数。出于优化目的,甚至允许编译器根据具体情况更改评估顺序。

如果评估顺序很重要,则需要重写代码。依赖于未指定行为的代码总是一个错误,可能是一个非常微妙的错误,不会立即浮出水面。

未指定的行为与未定义的行为不同,这意味着任何事情都可能发生,包括程序变得混乱或崩溃。