作者:非妃是公主
专栏:《C++》
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
首先,先来看一下三者的定义。
优先级,就是运算的先后顺序,例如我们小学学的先算乘除,后算加减。在c++中也是一样,先*,/,后+,-;
来看下面的c语言代码:
// An highlighted block
cout << 1 + 2 * 3 << endl;
根据先算乘法后算加法的优先级,输出的结果为7;
结合性,在优先级相同的条件下,是从左到右(左结合)还是从右到左(右结合)计算。
代码片:
// An highlighted block
cout << 2 - 1 - 1 << endl;
从左到右计算,输出的结果为0,而不是从右到左得到的2;
求值次序,这个是重点,它是指在一个表达式中优先计算的操作对象(例如:在两个操作对象的表达式(A=B+C)中,是先计算B呢,还是先计算C呢?)
注意:B,C为操作对象,既可为表达式也可为某个对象;
乍一看上去,有的小伙伴可能会想:
首先,根据优先级,先计算B或C。
其次,根据结合性,加法为左结合,将B和C相加。
最后,顺其自然得到了A的值;
于是,问题产生了,先算B和先算C有什么区别,仿佛对结果都没什么影响呀!
就好比A=(1+2)+(3+4)(其中,B为(1+2),C为(3+4));
无论我们先算(1+2)还是(3+4)结果都是一样的。
那么求值次序到底有什么用?
但是,我们忽略了一个问题:我们举的例子都是具体的数字,而代码中往往都是对象(例如内置类型对象,int a,double b等)
这时,我们再来看一个例子:
// An highlighted block
int a = 1, b = 2, c = 3, d = 4;
int B = a + b;
int C = c + d;
int A = B + C;
cout << "A的值为:" << A << endl;
emmm…好像,也没有影响。
那我们再来看一个例子:
// An highlighted block
int i = 0, j;
j = i * 2 + i++;
cout << "j的值为:" << j << endl;
在这个例子中,如果我们先算i*2,再算i++,结果是0;
而如果先算i++,再算i*2,结果为2;
产生了不同的结果,于是到底是先算左操作对象(i * 2)还是先算右操作对象(i++)呢?
这就是求值次序的作用吗???(实则不然)
其实,i++要等到分号结束(即语句结束在执行全部副作用)后再进行++操作,所以,在j的赋值表达式中,i的值一直为0; 并未进行变化。
于是,无论先算左右操作对象,结果都会是0,而不会是2;
所以上面的那个例子是依旧错误的(他应该是一个副作用和序列点的好例子)
我还测试了以下代码:
// An highlighted block
#include<iostream>
using namespace std;
int f1(int a) {
int b = a * 2;
return b;
}
int& f2(int& a) { //这里注意是地址传递;
a++;
return a;
}
int main() {
int i = 0, j;
cout << f1(i) + f2(i) << endl;
}
以上代码VS2019输出的值为1;说明先计算的f1后计算的f2;否则,若先f2后f1,输出值会是3;
以上我认为才是一个求值次序的例子。
不难发现,求值次序只在两个操作对象中有相同的对象,而发生相互影响,才发挥作用(在最后一个例子中,我们的左右操作对象中都有i这个对象)
至此求值次序的作用也就说清楚了。
下面列举一下,c99中还规定了四个求值次序:
// An highlighted block
||//与,先左后右
&&//或,先左后右
?: //三目运算符,先左后右
,//逗号运算符,从左到右
c99标准中只规定了这四种求值次序(c++11中也未改变)。而上面的最后一个例子的结果到底是0还是2,则要根据编译器而定。在VS2019中j的值为0。
大家的赞,是对我最大的支持,谢谢。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130618.html