C 语言中 && 和 || 优先级、结合性
 
分析下题的答案

 
C 语言运算符的优先级和结合性
首先,要知道 C 语言运算符的优先级和结合性。
 查阅资料得知:&& 的优先级比 || 高,结合性是从左往右。运算时,会把 && 左边的表达式看做一个整体。
 
 
分析几个简单的示例
第 1 个示例
先来几个简单的示例,进行分析:
#include <stdio.h>
int main()
{
	int a = 1, b = 0;
	printf("%d\n", b && a || b);
	printf("%d\n", a || b && a);
	printf("%d\n", a || b && b);
	return 0;
}
/*
运行结果:
0
1
1
*/
第一条语句
printf("%d\n", b && a || b);
- &&优先级比- ||高,会先执行- b这个表达式。- b的结果为- 0,C 语言中- 0为假。- &&的特性:只要任何一边的结果为假,整个表达式的结果即为假。
- b的结果已经为假,就不会再去理会右边整个- a || b,直接短路并返回结果,不往后面走了。
第二条语句
printf("%d\n", a || b && a);
- &&优先级比- ||高,- &&左边的所有内容都会被看做为一个整体,先去执行- &&左边的表达式- a || b。
- a为真,- ||一样也会短路,任意表达式为真,整个表达式即为真。
- ||左边已经短路了,同样也不会再去管右边的表达式- b && a了。直接返回- 1,结束本条语句。
第三条语句
printf("%d\n", a || b && b);
- 同样先去执行 &&左边的a || b表达式。
- a为- 1,- ||短路并返回结果,后面的表达式不会再去计算了。
 
第 2 个示例
#include <stdio.h>
int main()
{
	int a = 1, b = 0;
	printf("%d\n", b || a && a);
	return 0;
}
/*
运行结果:
1
*/
b || a && a
- &&的优先级比- ||高,会先去执行- &&左边的- b || a。(注:- b || a是- &&左边的一个整体)。
- b || a中,同样也先执行左边的- b,- b为- 0,此时- ||不会短路,它要继续去计算右边的结果。右边的- a为- 1,整个- b || a表达的结果为- 1。
- 现在的表达式是:1 && a。a为1,&&的两边都为1,表达式为1。
- 计算完毕,返回结果 1。
 
第 3 个示例
#include <stdio.h>
int main()
{
	int a = 1, b = 0, c = 1;
	printf("%d\n", b || a && c && b);
	return 0;
}
/*
运行结果:
0
*/
表达式 b || a && c && b 中,有两个 &&,按照结合性,是从左往右计算。
- 把表达式劈成两瓣,就是:b || a && c和&& b。
- 先去执行 b || a && c,再次把这个表达式劈开:b || a和&& c。
- 从左往右,先会计算 b || a这个表达式的左边b,b的结果为0,然后计算a,a为1,于是b || a的结果为1。现在表达式为:1 && c,c也是1。表达式b || a && c的结果为1。
- 现在的表达式为:1 && b。&&需要计算两边的结果才能判定是否都为1。但是,b为0。只要有一个结果为0,整个&&表达式就为0。返回结果0。
小结
&& 和 || 同时在一条语句中,要记住 && 的优先级比 || 高,&& 左边的所有一切都是一个完整的整体。
再来一题
#include <stdio.h>
int main()
{
	int a = 1, b = 0, c = 0;
	c = (a+=10) || (b+=5) && (b+=5);
	printf("a=%d, b=%d, c=%d\n", a, b, c);
	a = 1, b = 0;
	c = (a+=10) || ( (b+=5) && (b+=5) );
	printf("a=%d, b=%d, c=%d\n", a, b, c);
	a = 1, b = 0;
	c = ( (a+=10) || (b+=5) ) && (b+=5);
	printf("a=%d, b=%d, c=%d\n", a, b, c);
	return 0;
}
/*
运行结果:
a=11, b=0, c=1
a=11, b=0, c=1
a=11, b=5, c=1
*/
第一条语句
c = (a+=10) || (b+=5) && (b+=5);
- 有三个“加后赋值语句”,都被小括号包裹了起来。三个优先级是平级的,就会去看 &&和||的优先级。
- &&高于- ||,先会去执行- &&左边的- (a+=10) || (b+=5)这个表达式。
- 再在这个 (a+=10) || (b+=5)表达式中,先执行(a+=10),现在a的结果为11,且运行结果为真,即为1。
- 上述的表达式变成了 1 || (b+=5),遇到一个结果为真,||发生短路,不会再去管后面的(b+=5),更不会去管||后面的那些整体了。
- 直接给 c赋值为1,并结束本条语句。
 
第二条语句
c = (a+=10) || ( (b+=5) && (b+=5) );
- 在第一条语句基础上,把 ||后面的语句用小括号再次包裹了起来。现在变成了 2 个小括号语句:(a+=10) || ( ... )。
- 先执行 ||左边的小括号中的表达式,a = a + 10,a的结果为11。表达式运行结果为真,即为1。
- 现在表达式是:c = 1 || ( (b+=5) && (b+=5) );。||发生短路并将1赋值给c后,结束整条语句。
 
第三条语句
c = ( (a+=10) || (b+=5) ) && (b+=5);
- 小括号提升优先级,语句是:c = ( ... ) && (b+=5);。
- 先执行 &&左边小括号中的语句( (a+=10) || (b+=5) )。
- 在 ( (a+=10) || (b+=5) )中,先执行(a+=10)。a被赋值为11,语句运行结果为1,||发生短路,不会去计算后面的(b+=5)。但是,此条语句中的(b+=5)是被包裹在小括号中的。不执行(b+=5)该条语句,是因为被||短路了。出了小括号之后,还会有... && (b+=5)这条语句的&&右边需要去被执行。
- 现在的语句是:c = 1 && (b+=5);。左边的结果为真,但&&还需要右边的结果。b+=5,b被赋值为5,语句运行结果为1。
- 两边都为 1,将1赋值给c。
回到最初的问题
#include <stdio.h>
int main()
{
	int a = 2, b = 2, c = 2;
	c = (a = 3) || (a = 4) && (b = 5);
	printf("a=%d, b=%d, c=%d\n", a, b, c);
	return 0;
}
/*
运行结果:
a=3, b=2, c=1
*/
c = (a = 3) || (a = 4) && (b = 5);
- 语句也是由 3 个小括号包裹着。3 个小括号优先级是平级的,那么就要看 &&和||的优先级谁更高,显然是&&的优先级高。
- 于是表达式 (a = 3) || (a = 4)这个整体会先被执行。
- (a = 3) || (a = 4)这个整体中,又先执行- (a = 3)。给- a赋值为- 3,表达式运行结果为- 1(即为真)。只要一个条件为真,- ||就会发生短路,不再去理会- ||后面- (a = 4) && (b = 5)这一大坨东西。
- 把 1赋值给c,结束本条语句。
参考文献
C 语言运算符的优先级和结合性










