——操作符的行为
Behavior of -- operator
--x
和x-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)
现在我们可以将这些规则应用到这个表达式:
-
+
操作符的两个操作数的求值是无序的。编译器可以自由地先求_suma
,然后求sumaRec(--_suma)
,或者反过来求。 -
--_suma
的值计算和副作用在sumaRec
调用之前进行排序。 - 关于
sumaRec
调用本身,一切都是不确定的排序;也就是说,编译器可以在sumaRec
函数中的语句执行之前或之后计算_suma
,但不能在执行过程中计算CC_14。 -
+
的两个操作数的值计算,而不是副作用,在+
运算符的结果计算之前进行排序。
特别是,因为标量对象(_suma
)的副作用(存储减少的值)相对于使用相同标量对象的值(计算+
的第一个操作数的值)的值计算是无序的,所以行为是未定义的。
符合标准的编译器可以做以下任何事情:
- 评估
_suma
第一,--_suma
第二,sumaRec
第三 -
--_suma
优先,sumaRec
第二,_suma
第三 - 优先评估
--_suma
,_suma
第二,sumaRec
第三 - 首先执行
--_suma
的值计算,其次执行_suma
的值计算,第三执行--_suma
的副作用(存储减少的值),第四执行sumaRec
- 召唤鼻子恶魔,咬你的硬盘驱动器,或者其他任何它想做的事情。当行为未定义时,所有的赌注都是无效的。
值得强调的是,操作符优先级和求值顺序是完全不同的事情。运算符优先级意味着像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
前缀减量正在修改您使用的变量,不仅可以将其发送给函数,还可以在序列计算中使用。这就是为什么你最终会得到一个错误的计算。
我建议您将减法放在临时变量中,然后将该变量传递给您的函数。
- 为什么map有操作符[],set没有
- 我可以将C 17 Capture lambda ConstexPR转换操作符的结果用作函数指针模板非类型参数吗?
- c++新操作符通过libstdc++占用大量内存(67MB)
- 复制/移动操作符是否可以安全地用于实现复制/移动分配操作符
- 提升::精神::因果报应使用有条件的替代操作符(|)
- 促进几何体操作符
- 如果操作符delete没有实现,为什么不编译它
- 在使用放置新操作符时,我真的需要担心对齐问题吗
- 我怎样才能让getline操作符工作
- 在重载的全局new操作符中使用静态对象会导致核心转储运行时错误
- 提升ipc new和delete操作符
- 在c++中使用new操作符动态分配数组
- 操作符的大小在C++
- 如何将向量中的对象传递给操作符
- 一个更容易的拷贝分配操作符实现
- 如何重写复杂的c++代码行(嵌套的三元操作符)
- boost::make_shared没有调用(放置)操作符new
- 新操作符(以及malloc)无法分配~450MB的内存
- 类、异常和操作符
- 当delete操作符释放内存时,我为什么需要析构函数