C++ 我们如何预测以下C++;节目

C++ 我们如何预测以下C++;节目,c++,c++11,gcc,g++,C++,C++11,Gcc,G++,我对代码的输出感到困惑。 这取决于我运行代码的编译器。为什么会这样 #include <iostream> using namespace std; int f(int &n) { n--; return n; } int main() { int n=10; n=n-f(n); cout<<n; return 0; } #包括 使用名称空间std; 内特f(内特和内特) { n--;

我对代码的输出感到困惑。 这取决于我运行代码的编译器。为什么会这样

#include <iostream>
using namespace std;
int f(int &n)
{   
    n--;
    return n;
}
int main()
{
      int n=10;
      n=n-f(n);
      cout<<n;
      return 0;
}
#包括
使用名称空间std;
内特f(内特和内特)
{   
n--;
返回n;
}
int main()
{
int n=10;
n=n-f(n);

在C++03中,在没有插入C++03序列点的情况下,修改变量并在同一表达式中使用其值是未定义的行为

C++03第5/4节: 在上一个 下一个序列点,一个标量对象的存储值应通过计算最多修改一次 此外,只能通过访问先验值来确定要存储的值。 完整表达式子表达式的每个允许顺序应满足本段的要求 表达式;否则该行为未定义

未定义的行为UB为编译器提供了一个优化的机会,因为它可以假设UB不会出现在有效的程序中

但是,在C++的所有UB规则中,很难对源代码进行推理。
在C++中,11个序列点被替换为之前已排序、不确定排序和未排序的关系:

C++11§1.9/3 给定任意两个评估A和B,如果 A在B之前排序,则A的执行应先于B的执行。如果A在B之前未排序 B和B在A之前未排序,则A和B未排序。[注:未排序的执行 评估可能重叠。-结束注释]评估A和B的顺序不确定 在B之前排序,或B在A之前排序,但未指定是哪个

使用新的C++11序列关系规则,所讨论代码中函数的修改根据变量的使用不确定顺序,因此代码具有未指定的行为,而不是Eric M Schmidt在中指出的未定义的行为。本质上,这意味着没有危险对于后台进程或其他可能的UB效果,并且该行为是合理的。这里有两种可能的行为,通过函数调用进行的修改是在使用值之前完成的,或者是在使用值之后完成的

为什么是未指明的行为:

C++11§1.9/15: 调用函数(包括其他函数调用)中未特别指定的每个求值 在被调用函数体的执行之前或之后进行的排序是不确定的,使用 关于被调用函数的执行

“未指定行为”的含义是:

C++11§1.3.25: 未指明的行为
行为,对于格式良好的程序构造和正确的数据,这取决于实现 [注意:实现不需要记录发生的行为。可能的 行为通常由本国际标准描述。-尾注]

转让影响的修改没有问题的原因:

C++11§5.17/1 在所有情况下,赋值顺序都在值之后 计算右操作数和左操作数,然后计算赋值表达式的值

这与C++03也有很大不同



正如这个答案的激烈编辑所显示的,在Eric的评论之后,这类问题并不简单!我能给出的主要建议是尽可能多地说“不”™ 对于由微妙或非常复杂的规则控制的效果,语言的各个角落。简单的代码更有可能是正确的,而所谓的聪明的代码没有明显更快的机会。

给定的代码没有未定义的行为,只是未指定的行为。@EricMSchmidt:这是一个有趣的想法。在C++1中1术语,您是说函数调用在这里没有“对标量对象的副作用”,还是说相对于该对象的使用,它不是未排序的?它不是未排序的,而是不确定的排序,因为减量操作发生在函数f而不是main中。“调用函数(包括其他函数调用)中未在被调用函数体执行之前或之后以其他方式明确排序的每个求值,都是相对于被调用函数的执行进行不确定排序的。”(1.9/15)哦,谢谢,反正我需要修正这个答案,因为它混合了C++03和C++11规则。我原以为它们是兼容的,但现在看来它们还没有完成[[[[[[[[[[[[[[[[[[[[[[