——操作符的行为

Behavior of -- operator

本文关键字:操作符      更新时间:2023-10-16

--xx-1有什么区别?我有一个计算前n个数和的方法我尝试使用100,结果如下:

int sumaRec(int _suma){
    if (_suma > 0)
    {
        return _suma + sumaRec(--_suma);
    }
    else
        return 0;
}

当我放--_suma的结果是4950,当我放_suma -1的结果是5050

有谁能解释为什么吗?请。

这是对求值顺序问题的详细说明。

以下是c++ 11标准对求值顺序的规定:

  • 在计算与下一个完整表达式相关的每个值计算和副作用之前,对与完整表达式相关的每个值计算和副作用进行排序。(§1.9 [intro.execution]/p15)
  • 运算符的操作数的值计算在运算符结果的值计算之前进行排序。(§1.9 [intro.execution]/p15)
  • 单个操作符和单个子表达式的操作数求值表达式是无序的。(§1.9 [intro.execution]/p15)
  • 调用函数时(无论函数是否内联),与任何参数表达式或指定被调用函数的后缀表达式相关的每个值计算和副作用都在被调用函数体中的每个表达式或语句执行之前进行排序。(§1.9 [intro.execution]/p16)
  • 调用函数(包括其他函数调用)中的每个求值(在被调用函数体执行之前或之后没有明确排序)相对于被调用函数的执行而言是不确定排序的。(§1.9 [intro.execution]/p16)

如果标量对象上的副作用相对于同一标量对象上的另一个副作用或使用同一标量对象的值进行的值计算是无序的,则该行为是未定义的。(§1.9 [intro.execution]/p15)

现在我们可以将这些规则应用到这个表达式:

  1. +操作符的两个操作数的求值是无序的。编译器可以自由地先求_suma,然后求sumaRec(--_suma),或者反过来求。
  2. --_suma的值计算和副作用在sumaRec调用之前进行排序。
  3. 关于sumaRec调用本身,一切都是不确定的排序;也就是说,编译器可以在sumaRec函数中的语句执行之前或之后计算_suma,但不能在执行过程中计算CC_14。
  4. +的两个操作数的值计算,而不是副作用,在+运算符的结果计算之前进行排序。

特别是,因为标量对象(_suma)的副作用(存储减少的值)相对于使用相同标量对象的值(计算+的第一个操作数的值)的值计算是无序的,所以行为是未定义的。

符合标准的编译器可以做以下任何事情:

  1. 评估_suma第一,--_suma第二,sumaRec第三
  2. --_suma优先,sumaRec第二,_suma第三
  3. 优先评估--_suma, _suma第二,sumaRec第三
  4. 首先执行--_suma的值计算,其次执行_suma的值计算,第三执行--_suma的副作用(存储减少的值),第四执行sumaRec
  5. 召唤鼻子恶魔,咬你的硬盘驱动器,或者其他任何它想做的事情。当行为未定义时,所有的赌注都是无效的。

值得强调的是,操作符优先级和求值顺序是完全不同的事情。运算符优先级意味着像f() + g() * h()这样的表达式被编译器解释为f() + (g() * h())而不是(f() + g()) * h(),但是不能保证f()g()h()将以任何特定的顺序求值。事实上,如果这个表达式在同一代码中出现两次,编译器甚至不需要一致:计算顺序可以是f(), g(), h(), g(), f(), h()

编辑:要注意GCC,如预期的那样,对这段代码发出警告:

g++ -march=native -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
main.cpp: In function 'int sumaRec(int)':
main.cpp:9:39: warning: operation on '_suma' may be undefined [-Wsequence-point]
         return _suma + sumaRec(--_suma);
                                       ^

在编译时启用完整的警告总是一个好主意。

的基本区别是,当您执行x-1时,x的值保持不变。但是当您执行--x时,x的值是递减的。

,

x=4;
y=x-1;

现在,在这种情况下,x是4 y是3。现在,对于x=4,

y = --x;

现在x和y都是3

前缀减量正在修改您使用的变量,不仅可以将其发送给函数,还可以在序列计算中使用。这就是为什么你最终会得到一个错误的计算。

我建议您将减法放在临时变量中,然后将该变量传递给您的函数。