在函数参数中使用post-increment

ord*_*ary 7 c++

当我运行此代码时,输​​出为11,10.

那到底为什么会这样?有人可以给我一个解释,希望能启发我吗?

谢谢

#include <iostream>
using namespace std;

void print(int x, int y)
{ 
    cout << x << endl;
    cout << y << endl;
}
int main()
{
    int x = 10;
    print(x, x++);
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*aul 16

C++标准状态(第16年1月9日的说明):

与不同参数表达式相关联的值计算和副作用未被排序.

换句话说,它是未定义的和/或编译器相关的,在它们的值传递给函数之前,参数的计数顺序是哪个.所以在一些编译器(首先评估左参数)上,代码将输出,10, 10而在其他编译器上(首先评估正确的参数)将输出11, 10.通常,您不应该依赖未定义的行为.

为了帮助您了解这一点,想象函数被调用,像这样(不,这是它究竟是如何工作的,它只是想起来,这将有助于您了解测序的简单方法)之前每个参数表达式求值:

int arg1 = x;       // This line
int arg2 = x++;     // And this line can be swapped.
print(arg1, arg2);
Run Code Online (Sandbox Code Playgroud)

C++标准表示两个参数表达式未被排序.因此,如果我们在这样的单独行上写出参数表达式,它们的顺序应该不重要,因为标准说它们可以按任何顺序进行评估.有些编译器可能会按照上面的顺序对它们进行评估,其

int arg2 = x++;     // And this line can be swapped.
int arg1 = x;       // This line
print(arg1, arg2);
Run Code Online (Sandbox Code Playgroud)

这使得很明显如何arg2保持价值10,同时arg1保持价值11.

您应始终在代码中避免此未定义的行为.


Alo*_*ave 7

总的来说:

 print(x, x++);
Run Code Online (Sandbox Code Playgroud)

导致未定义的行为.一旦程序有一个未定义的行为,它就不再是一个有效的C++程序,而且任何行为都是可能的.所以找到这样一个程序的推理是没有意义的.


为什么这个未定义的行为?

让我们一步一步地评估程序,直到我们可以毫无疑问地证明它导致未定义的行为.

函数参数的评估顺序是Unspecified [Ref 1].

未指定意味着允许实现按照其需要实现此特定功能,并且不需要记录有关它的详细信息.

将以上规则应用于函数调用:

print(x, x++);
Run Code Online (Sandbox Code Playgroud)

实现可能会将其评估为:

  • 从左到右或
  • 从右到左或
  • 任何神奇的顺序(如果有两个以上的函数参数)

简而言之,您不能依赖实现来遵循任何特定的顺序,因为它不是按照C++标准要求的.

在C/C++中,如果没有插入序列点,则不能多次读取或写入变量[参考文献2].如果这样做,则会导致未定义的行为.无论是否在上述函数中首先评估任一参数,它们之间没有序列点,只有在评估了所有函数参数后才存在序列点[参考文献3].

在这种情况下x,访问时没有插入序列点,因此导致未定义的行为.

简单地说,最好编写任何不调用此类未定义行为的代码,因为一旦这样做,您就不能指望这样的程序有任何特定的行为.


[参考1] C++ 03标准§5.2.2.8
第8段:

[...]函数参数的评估顺序未指定.[...]


[参考2] C++ 03 5表达式[expr]:
第4段:

....
在前一个和下一个序列点之间,标量对象应通过表达式的计算最多修改一次其存储值.此外,只能访问先前值以确定要存储的值.对于完整表达式的子表达式的每个允许排序,应满足本段的要求; 否则行为未定义.


[参考3] C++ 03 1.9程序执行[intro.execution]:
第17段:

在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有)之后,都会有一个序列点.


小智 5

x++ 是一个函数参数,它们可能以未指定的顺序进行计算,这意味着行为未定义且不可移植(或合法)。