优先级,结合性,求值次序三者的的区分及作用

首先,先来看一下三者的定义。

优先级,就是运算的先后顺序,例如我们小学学的先算乘除,后算加减。在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。

大家的赞,是对我最大的支持,谢谢。

猜你喜欢

转载自blog.csdn.net/myf_666/article/details/112971512