龙空技术网

技术文章:C语言逻辑运算符的短路,以及scf框架对它的实现

底层技术栈 604

前言:

现在兄弟们对“c语言中三种逻辑运算符”大概比较重视,咱们都需要剖析一些“c语言中三种逻辑运算符”的相关内容。那么小编同时在网上收集了一些对于“c语言中三种逻辑运算符””的相关知识,希望姐妹们能喜欢,我们快快来学习一下吧!

逻辑运算符的短路,是C语言的一个基本语法。

在逻辑与运算&&连接的2个表达式里,只要第1个表达式为false,那么总结果就为false,后续的其他表达式就不需要计算了。

在逻辑或运算||连接的2个表达式里,只要第1个表达式为true,那么总结果就为true,后续的其他表达式也不需要计算了。

这就是逻辑运算符的短路。

与运算的短路,可以用于结构体指针取成员时的判断。

例如:

if (f && f->ops && f->ops->read && (ret = f->ops->read()) > 0)

return ret;

这2行代码里的与运算,是判断函数指针有关的成员变量是否为NULL,以避免空指针的使用。

当f为NULL时,第1个逻辑表达式的结果就是false,程序会自动跳过后面的各个表达式,避免因空指针而导致程序死掉。

if (king->x + king->y == queen->x + queen->y || king->x - king->y == queen->x - queen->y)

return 1;

上面的代码,是国际象棋里判断king与queen在不在同一条斜线上。

在同一条斜线上时,xy坐标的和或者差相同,2个条件里只需要1个成立就行。

如果第一个表达式成立,就会触发||运算符的短路。

scf编译器框架里,&&和||的短路是在中间代码生成时处理的。

&&运算的短路处理,首先计算第一个表达式,并且获取它的比较运算符。

&&运算在比较条件为false时短路,所以它的跳转条件与比较运算符本身是反着的。

if (a ==b && b == c) {}

这种比较,当a != b时才会越过后面的b == c。

比较两个数是否相等,在汇编里是做减法,然后看结果是不是0。

也就是说,if (a == b)在汇编里是 if (a - b == 0)。

所以,当a == b时,cpu会设置零标志:eflags寄存器的ZF标志位为1。

所以,短路跳转条件是jnz,a - b != 0时做短路跳转。

对于浮点数的大于和小于的比较,在x64里与整数不同。

浮点数使用above和below,而整数使用greater和less,

所以:

浮点数的 >= 是jae,<= 是jbe;

整数的 >= 是jge,小于等于是jle。

如果是逻辑非运算,或者直接比较一个数是不是0,需要使用test指令。

if (!p) 和 if (p) 的比较都是 test p,p,然后根据结果是不是0来跳转。

test指令,在汇编里使用按位与运算。

当p == NULL的时候,它与它自己的按位与运算的结果肯定是0。

这个运算,可以被用来判断指针是不是NULL。

||运算符的短路跳转条件,跟它的第一个表达式的比较条件是一致的,因为它是条件为true时短路。

总的来说,||和&&的处理过程一样,除了跳转条件有点区别(不再细说)。

短路跳转的添加

短路跳转的添加,如上图,跳转到第2个表达式的后面。

如果第2个表达式后面还有逻辑运算符的话,它同时也是这个运算符的第1个表达式,会触发级联的短路跳转。

示例代码

接下来3张图,是生成的中间代码,已经划分了基本块:

对于级联跳转,我没有做进一步的跳转优化。

i > 0

j > 1

k > 2

最后2张图,是或运算符的处理代码,不再细说了。

标签: #c语言中三种逻辑运算符