【新书推荐】5.1 逻辑运算符

第五章 逻辑运算

       本章讲解逻辑运算符与逻辑运算,移位运算符与移位运算。

本章学习知识概要:

      逻辑运算符

      位运算符

5.1 逻辑运算符

本节必须掌握的知识点:

   示例十六

   代码分析

   汇编解析

5.1.1 示例十六

逻辑运算符包括逻辑与、逻辑或、逻辑非,如表5-1所示。

运算符

表达式

说明

&&逻辑与(并且)

条件1&&条件2

两个条件同时为真时,结果为真

||逻辑或(或)

条件1||条件2

两个条件有一个为真时,结果为真

!逻辑非(非)

!条件

条件为真时,结果为假

条件为假时,结果为真

                                 表5-1逻辑运算符

&&逻辑与

语法格式:expr1 && expr2;

当两个条件同时为真时,结果为真;否则为假。(在C语言中,非0为真,0为假)。

举例

1 && 2 //真&&真 -->结果为真

0 && 1 //假&&真 -->结果为假;当expr1为假时,将直接返回假,不会再计算expr2。

-1 && 0 //真&&假 -->结果为假

2>3 && 2 //假&&真 -->结果为假;当expr1为假时,将直接返回假,不会再计算expr2。

||逻辑或

语法格式:expr1 || expr2;

当两个条件有一个为真时,结果为真;否则为假。

举例

0 || 1  //假||真 -->结果为真;当expr1为假时,会继续计算expr2。

0 || 0  //假||假 -->结果为假;当expr1为假时,会继续计算expr2,expr2为假,则为假(两个条件都为假时,结果为假)。

!逻辑非

语法格式:!expr;当条件为真时,结果为假;当条件为假时,结果为真。

举例

!0         //假 -->结果为真

!1         //真 -->结果为假

!(1>2)     //假 -->结果为真

■德摩根定律

对各条件取非,然后将逻辑与变为逻辑或,逻辑或变为逻辑与,然后再取其否定,结果和原条件一样。

举例

x && y 和 !(! x || !y )相等

x || y 和 !(! x && !y )相等

【注意】单目运算符 ‘-’取补码,单目运算符‘~’ 符号取反。

示例代码十六

/*

   逻辑运算符

*/

#include

#include

int main(void) {

    int  x = 2,y = 4,z = 6;

    int num;

    printf("请输入一个整数:");

    scanf_s("%d", &num);

    if (y < num && z > num)

        printf("两个条件表达式同时为真时,逻辑与表达式为真!\n");

    if (x == num || y == num)

        printf("其中任意一个表达式为真时,逻辑或表达式为真!\n");

    if (!num)

        printf("num为零时,逻辑非表达式为真!\n");

   

    printf("num符号取反之后的值是%d\n", -num); //取num的补码

    printf("num补码的值是%d\n", ~num); //num符号取反   

    system("pause");

    return 0;

}

输出结果:

测试1

请输入一个整数:5

两个条件表达式同时为真时,逻辑与表达式为真!

num补码的值是-5

num符号取反之后的值是-6

测试2

其中任意一个表达式为真时,逻辑或表达式为真!

num补码的值是-4

num符号取反之后的值是-5

测试3

请输入一个整数:0

num为零时,逻辑非表达式为真!

num补码的值是0

num符号取反之后的值是-1

5.1.2 代码分析

    示例十六代码中定义了3个变量x,y,z。然后有用户输入一个整数值存入变量num中。接下来3个if条件语句中各包含一个逻辑运算符&&、||、!。如果if语句条件为真,使用printf函数输出结果。最后一个printf语句使用单目运算符 “-”符号取反,然后输出结果。

       当我们需要同时判断多个条件表达式时,我们可以使用“&&”逻辑与运算符或者“||”逻辑或运算符将多个条件表达式连接起来。

如果使用“&&”逻辑与运算符,连接的两个条件表达式同时为真时,结果为真;如果其中一个条件表达式为假,则结果为假。可以尽量选择条件为假可能性较大的表达式前置,如果前置条件表达式为假,则结果为假,后置的条件表达式就无需判断了,这样可以提高程序的运行效率。

如果使用“||”逻辑或运算符,连接的两个条件表达式只要其中一个为真,则结果为真;如果两个表达式全部为假,则结果为假。我们可以选择条件为真可能性较大的表达式前置,当前置表示为真时,结果为真,后置的表达式就无需判断了。

符号取反单目运算符 ‘~’。取补码运算符‘-’并不是逻辑运算符。

5.1.3 汇编解析

汇编代码

    ;C标准库头文件和导入库

include vcIO.inc

.data  

x   sdword 2      

y   sdword 4

z   sdword 6

num sdword  ?

.const 

szMsg1 db "请输入一个整数:",0

szMsg2 db "%d",0

szMsg3 db "两个条件表达式同时为真时,逻辑与表达式为真!",0dh,0ah,0

szMsg4 db "其中任意一个表达式为真时,逻辑或表达式为真!",0dh,0ah,0

szMsg5 db "num为零时,逻辑非表达式为真!",0dh,0ah,0

szMsg6 db "num符号取反之后的值是%d",0dh,0ah,0

szMsg7 db "num补码的值是%d",0dh,0ah,0

.code  

start:

    ;输入整数num

    invoke printf,offset szMsg1

    invoke scanf,offset szMsg2,ADDR num

    ;

    mov eax,num

    .if (y < eax) && (z > eax)

        invoke printf,offset szMsg3

    .endif

    mov eax,num

    .if (x == eax) || (y == eax)

        invoke printf,offset szMsg4

    .endif

    .if !num

        invoke printf,offset szMsg5

    .endif

    ;补码

    mov eax,num

    neg eax

    invoke printf,offset szMsg7,eax;输出结果

    ;符号位取反

    mov eax,num

    not eax     ;not取反指令,各位取反,符号位不变

    mov num,eax

    invoke printf,offset szMsg6,num;输出结果

    ;  

    invoke _getch  

    ret            

end start

    输出结果与C代码相同。

    上述汇编代码使用了.if\.else\.endif高级汇编决策伪指令,与C语言中的if/else语句基本相同。C语言中的‘-’运算符对应汇编中的neg求补指令。C语言中的‘~’运算符对应汇编not取反指令。

反汇编代码

        int  x = 2,y = 4,z = 6;

00EF4ED2  mov         dword ptr [x],2 

    int  x = 2,y = 4,z = 6;

00EF4ED9  mov         dword ptr [y],4 

00EF4EE0  mov         dword ptr [z],6 

    int num;

    printf("请输入一个整数:");

00EF4EE7  push        offset string "\xc7\xeb\xca\xe4\xc8\xeb\xd2\xbb\xb8\xf6\xd5\xfb\xca\xfd\xa3\xba" (0EF7B30h) 

00EF4EEC  call        _printf (0EF104Bh) 

00EF4EF1  add         esp,4 

    scanf_s("%d", &num);

00EF4EF4  lea         eax,[num] 

00EF4EF7  push        eax 

00EF4EF8  push        offset string "%d" (0EF7B48h) 

00EF4EFD  call        _scanf_s (0EF138Eh) 

00EF4F02  add         esp,8 

    if (y < num && z > num)

00EF4F05  mov         eax,dword ptr [y] 

00EF4F08  cmp         eax,dword ptr [num] 

00EF4F0B  jge         main+82h (0EF4F22h) 

00EF4F0D  mov         eax,dword ptr [z] 

00EF4F10  cmp         eax,dword ptr [num] 

00EF4F13  jle         main+82h (0EF4F22h) 

        printf("两个条件表达式同时为真时,逻辑与表达式为真!\n");

00EF4F15  push        offset string "\xc1\xbd\xb8\xf6\xcc\xf5\xbc\xfe\xb1\xed\xb4\xef\xca\xbd\xcd\xac\xca\xb1\xce\xaa\xd5\xe6\xca\xb1\xa3\xac\xc2\xdf\xbc\xad\xd3@"... (0EF7E40h) 

00EF4F1A  call        _printf (0EF104Bh) 

00EF4F1F  add         esp,4 

        if (x == num || y == num)

00EF4F22  mov         eax,dword ptr [x] 

00EF4F25  cmp         eax,dword ptr [num] 

00EF4F28  je          main+92h (0EF4F32h) 

00EF4F2A  mov         eax,dword ptr [y] 

00EF4F2D  cmp         eax,dword ptr [num] 

00EF4F30  jne         main+9Fh (0EF4F3Fh) 

        printf("其中任意一个表达式为真时,逻辑或表达式为真!\n");

00EF4F32  push        offset string "\xc6\xe4\xd6\xd0\xc8\xce\xd2\xe2\xd2\xbb\xb8\xf6\xb1\xed\xb4\xef\xca\xbd\xce\xaa\xd5\xe6\xca\xb1\xa3\xac\xc2\xdf\xbc\xad\xbb@"... (0EF85E8h) 

00EF4F37  call        _printf (0EF104Bh) 

00EF4F3C  add         esp,4 

        if (!num)

00EF4F3F  cmp         dword ptr [num],0 

        if (!num)

00EF4F43  jne         main+0B2h (0EF4F52h) 

        printf("num为零时,逻辑非表达式为真!\n");

00EF4F45  push        offset string "num\xce\xaa\xc1\xe3\xca\xb1\xa3\xac\xc2\xdf\xbc\xad\xb7\xc7\xb1\xed\xb4\xef\xca\xbd\xce\xaa\xd5\xe6\xa3\xa1\n" (0EF7BECh) 

00EF4F4A  call        _printf (0EF104Bh) 

00EF4F4F  add         esp,4 

   

        printf("num补码的值是%d\n", -num);//取num的补码

00EF4F52  mov         eax,dword ptr [num] 

00EF4F55  neg         eax 

00EF4F57  push        eax 

00EF4F58  push        offset string "num\xb2\xb9\xc2\xeb\xb5\xc4\xd6\xb5\xca\xc7%d\n" (0EF7FA4h) 

00EF4F5D  call        _printf (0EF104Bh) 

00EF4F62  add         esp,8 

        printf("num符号取反之后的值是%d\n", ~num);//num符号取反

00EF4F65  mov         eax,dword ptr [num] 

00EF4F68  not         eax 

00EF4F6A  push        eax 

00EF4F6B  push        offset string "num\xb7\xfb\xba\xc5\xc8\xa1\xb7\xb4\xd6\xae\xba\xf3\xb5\xc4\xd6\xb5\xca\xc7%d\n" (0EF7CF8h) 

00EF4F70  call        _printf (0EF104Bh) 

00EF4F75  add         esp,8 

    上述C语言的反汇编代码,我们可以清晰的看到,C语言中的条件表达式被翻译为CMP/JCC条件判断语句:

    if (y < num && z > num)

00EF4F05  mov         eax,dword ptr [y] 

00EF4F08  cmp         eax,dword ptr [num] 

00EF4F0B  jge         main+82h (0EF4F22h)  ;如果y>=num,则跳转到0EF4F22h地址处

00EF4F0D  mov         eax,dword ptr [z] 

00EF4F10  cmp         eax,dword ptr [num] 

00EF4F13  jle         main+82h (0EF4F22h)  ;如果z<=num,则跳转到0EF4F22h地址处

00EF4F1A  call        _printf (0EF104Bh)

    if (x == num || y == num)

00EF4F22  mov         eax,dword ptr [x]

 

结论

1.C语言中的条件表达式最终被翻译为汇编语言中的JCC条件判断语句。

2.C语言语句和高级汇编的决策伪指令非常相似。

3.如果把汇编语言中的寄存器改为编译器自动选取,CMP/JCC条件判断语句简化为条件表达式,汇编语言就变成了C语言。

本文摘自编程达人系列教材《汇编的角度——C语言》。资料下载:www.bcdaren.com

你可能感兴趣的:(《汇编的角度——C语言》,汇编,c语言)