当我运行此代码时,输出为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.
您应始终在代码中避免此未定义的行为.
总的来说:
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段:
在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有)之后,都会有一个序列点.
| 归档时间: |
|
| 查看次数: |
5662 次 |
| 最近记录: |