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

5 c c++ undefined-behavior unspecified-behavior c++11

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

int f (int &x, int c) {
       c = c - 1;
       if (c==0) return 1;
       x = x + 1;
       return f(x,c) * x;
}
Run Code Online (Sandbox Code Playgroud)

选项包括:

  1. 3024
  2. 6561
  3. 55440
  4. 161051

我试着解释一下:


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


这个问题来自竞争性考试GATE,(见Q.no.-42).答案密钥由GATE"Marks to all"给出(表示没有选项正确.)key set-C,Q.no.-42.在某处解释为:

在GATE 2013中,所有人都给出了标记,因为C/C++中的相同代码会产生未定义的行为.这是因为*它不是C/C++中的序列点.必须替换正确的代码

return f(x,c) * x;
Run Code Online (Sandbox Code Playgroud)

 res = f(x,c);
 return res * x;
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*rtz 14

   return f(x,c) * x;
Run Code Online (Sandbox Code Playgroud)

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

  • @ user4791206"工作正常"是什么意思?既然你无法预测它会做什么,为什么你会说它发生了什么事它运作良好?有人预测它会以其他顺序进行评估并不会说它运行正常,是吗? (5认同)
  • 由于你已经给出了三个不同语言标签的问题,因此很难准确说明这个类别.它未定义或未指定.您可以查看您感兴趣的特定语言的规范. (2认同)

Lun*_*din 9

C++ 03第5章:

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

所以在这种情况下f(x,c) * x,操作数的评估顺序是未指定的,这意味着你不能知道左或右操作数是否会被首先评估.

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

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

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

  • 作为旁注,C++ 11中的相同文本是不同的,但具有相同的含义.我认为C++ 11(和C11)只是让文本更难理解,为什么我引用了旧版本的标准. (2认同)