为了减少程序的计算量,在进行逻辑运算时,C语言采用了在保持原逻辑运算正确性的同时,通过在已确定表达式的确切值的情况下,不计算其后式子的方式来削减运算量,这就是所谓“逻辑短路”
为何要进行逻辑短路
& 和 | 运算的法则
- 我们都知道
0 & 1 == 0, 0 | 1 == 1
,其实在这个过程中,无论是&
还是|
,符号两边的式子都被计算了一次,但对于第一个式子来说,只要第一个式子的结果是false
,在进行&
运算时,不管其后的结果如何,最后的结果一定为true
,相应的,对于|
,只要第一个式子是true
,其后的结果一定为true
.如果将这个性质放在日常代码实现中,我们可以看到
#include<stdio.h>
int a[4];
int main(){
++a[0] | ++a[1] | ++a[2] | a[3];
for(int i=0;i<4;++i) printf("a[%d]==%d ",i,a[i]);
puts("");
return 0;
}
- 运行结果:
注:
前置++
:先进行自增,再将自增后的结果加入逻辑运算中
后置++
:先加入逻辑运算,结果完成后再进行自增
- 但是对于整个式子来说,其实我们只要知道第一个是
true
,这个表达式的结果便已经显而易见,为了实现这种所谓“逻辑短路”的做法,C语言为我们提供了相应的运算符:&&
和||
&&和||运算
&&
运算规律和&
相同,||
运算规律和|
相同- 可视为二者的“加强版”
- 同样的式子,我们依然用代码举例
#include<stdio.h>
int a[4];
int main(){
++a[0] || ++a[1] || ++a[2] || a[3];
for(int i=0;i<4;++i) printf("a[%d]==%d ",i,a[i]);
puts("");
return 0;
}
- 运行结果:
- 另外的版本:
#include<stdio.h>
int a[4];
int main(){
++a[0] && 0 && ++a[2] && ++a[3];
for(int i=0;i<4;++i) printf("a[%d]==%d ",i,a[i]);
puts("");
return 0;
}
- 运行结果:
- 在上面的代码中,
a[0]
的运算结果为1
,&&
不进行短路,这时候进行一次运算得到0
,在第二个&&
时因为前面的式子结果为0
,其后的式子一律不参与计算,即a[2]
和a[3]
的自增无意义
更复杂些的式子
- 现在你已经掌握了对逻辑短路最基本的认识,为了方便以后样例的解释,我先贴出C语言中常用的运算符优先级表
- 我们可以举别的更加有趣的例子:
- 下面式子的值是多少?
#include<stdio.h>
int a[4];
int main(){
a[1]=4,a[2]=1,a[3]=0;
a[0]= a[1]++==4 || a[2]++&&a[3]++;
a[0]== ? a[1]==? a[2]==? a[3]==?
return 0;
}
- 显然不用理睬最后的取值符号,即使
++
的优先级高于==
,在进行逻辑运算的时候原则一定优先进行逻辑判断,在这个式子中a[1]==4
结果为true
,随后a[1]
自增为5
,前面的语句结束 - 这时候
||
的前面结果为true
,在存在逻辑短路的情况下,依旧不用管高于它优先级的++
和&&
,直接整个式子判断为true
,后续的自增运算符全部作废,显然易得答案 a[0]==1 a[1]==5 a[2]==0 a[3]==0
- 按照相似的原理,自然可以依旧举出一个类似的简单例子
#include<stdio.h>
int a[6];
int main(){
a[0]++ && a[1]++ || a[2]++ && a[3]++ || a[4]++ && a[5]++;
//各个变量的值分别是多少?
return 0;
}
- 在逻辑表达式中
&&
和||
并存时,一方面要注意二者的优先级关系,另一方面要注意逻辑短路的情况,而这类式子谨遵一个重要原则:
只要能确定表达式的结果,还没有进行的运算不再继续 - 如何理解?
- 来看示例中已经给出的例子
- 首先进行逻辑运算
a[0]&&
,前面的值为0,其后的a[1]++
忽略,a[0]
自增,接着到||
,因为前面的值为0
无法进行短路,故执行a[2]&&
,值为0
,其后a[3]++
忽略,a[2]
自增,最后二者0 || 0 == 0
,无法进行短路,执行a[4]&&
,结果以此类推,最后结果为
a[0]==1 a[1]==0 a[2]==1 a[3]==0 a[4]==1 a[5]==0
- 真的要造这类无意义又笨蛋的一长串式子很简单,如果真的喜欢钻研建议读者自己造并运行代码进行验证,下课!