C语言的位运算操作包括两类,逻辑运算操作和逻辑移位操作。

逻辑运算操作

C语言提供了四种按位逻辑操作符,分别是按位取反,按位与,按位或,按位异或。在编译时,编译器会根据操作数的宽度分别转换为不同的指令。

操作

C语言操作符

汇编指令

按位取反

~

notb、notw、notl

按位与

&

andb、andw、andl

按位或

l

orb、orw、orl

按位异或

^

xorb、xorw、xorl

注意: C语言的逻辑与(&&)、逻辑或(||)、逻辑非(!)并没有对应的机器指令,而是由多条指令联合来实现这些功能,完成以变量为单位的逻辑操作。

下面我们以一个简单的C语言程序test.c来了解逻辑运算操作过程。

#include

void main()

{

int a=5;

unsigned int b=3;

short c=5;

int d=0;

a = ~a;

b = ~b;

c = ~c;

d = a&b;

d = a^b;

d = a|b;

return;

}

利用gcc命令将其进行编译成可执行文件。

gcc -o0 -m32 -g test.c -o test

利用objdump命令进行反汇编并将其重定向到test.txt文件方便查看。

objdump -S test>test.txt

main函数所对应的汇编指令如下所示。

000004ed :

#include

void main()

{

4ed:55 push %ebp

4ee:89 e5 mov %esp,%ebp

4f0:83 ec 10 sub $0x10,%esp

4f3:e8 48 00 00 00 call 540 <__x86.get_pc_thunk.ax>

4f8:05 e4 1a 00 00 add $0x1ae4,%eax

int a=5;

4fd:c7 45 f4 05 00 00 00 movl $0x5,-0xc(%ebp)

unsigned int b=3;

504:c7 45 f8 03 00 00 00 movl $0x3,-0x8(%ebp)

short c=5;

50b:66 c7 45 f2 05 00 movw $0x5,-0xe(%ebp)

int d=0;

511:c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)

a = ~a;

518:f7 55 f4 notl -0xc(%ebp)

b = ~b;

51b:f7 55 f8 notl -0x8(%ebp)

c = ~c;

51e:66 f7 55 f2 notw -0xe(%ebp)

d = a&b;

522:8b 45 f4 mov -0xc(%ebp),%eax

525:23 45 f8 and -0x8(%ebp),%eax

528:89 45 fc mov %eax,-0x4(%ebp)

d = a^b;

52b:8b 45 f4 mov -0xc(%ebp),%eax

52e:33 45 f8 xor -0x8(%ebp),%eax

531:89 45 fc mov %eax,-0x4(%ebp)

d = a|b;

534:8b 45 f4 mov -0xc(%ebp),%eax

537:0b 45 f8 or -0x8(%ebp),%eax

53a:89 45 fc mov %eax,-0x4(%ebp)

return;

53d:90 nop

}

53e:c9 leave

53f:c3 ret

由以上代码可以看出a,b,c取反的三个操作分别对应以下指令。

a = ~a;

518:f7 55 f4 notl -0xc(%ebp)

b = ~b;

51b:f7 55 f8 notl -0x8(%ebp)

c = ~c;

51e:66 f7 55 f2 notw -0xe(%ebp)

其中变量a和变量b的取反指令都是notl,处理的是4字节的变量。而变量c的取反指令执行的是notw,执行的是2字节的变量。这也就说明了编译器会根据操作数的宽度分别转换为不同的指令。

下表给出C语言基本数据和类型和IA-32操作数类型的对应关系

C语言声明

汇编指令长度后缀

存储长度

(unsigned) char

b

8

(unsigned) short

w

16

(unsigned) int

l

32

(unsigned) long int

l

32

(unsigned) long long int

-

2 $imes$ 32

char *

l

32

float

s

32

double

l

64

long double

t

80/96

仍然以下面这样一个简单的C语言程序来理解逻辑与(&&)、逻辑或(||)、逻辑非(!)和按位逻辑操作符的区别。

#include

void main()

{

int a=5;

unsigned int b=3;

short c=5;

int d=0;

a = !a;

b = !b;

c = !c;

d = a&&b;

d = a||b;

return;

}

利用gcc命令将其进行编译,objdump命令进行反汇编之后,main函数所对应的汇编指令如下所示。

000004ed :

#include

void main()

{

4ed:55 push %ebp

4ee:89 e5 mov %esp,%ebp

4f0:83 ec 10 sub $0x10,%esp

4f3:e8 82 00 00 00 call 57a <__x86.get_pc_thunk.ax>

4f8:05 e4 1a 00 00 add $0x1ae4,%eax

int a=5;

4fd:c7 45 f4 05 00 00 00 movl $0x5,-0xc(%ebp)

unsigned int b=3;

504:c7 45 f8 03 00 00 00 movl $0x3,-0x8(%ebp)

short c=5;

50b:66 c7 45 f2 05 00 movw $0x5,-0xe(%ebp)

int d=0;

511:c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)

a = !a;

518:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

51c:0f 94 c0 sete %al

51f:0f b6 c0 movzbl %al,%eax

522:89 45 f4 mov %eax,-0xc(%ebp)

b = !b;

525:83 7d f8 00 cmpl $0x0,-0x8(%ebp)

529:0f 94 c0 sete %al

52c:0f b6 c0 movzbl %al,%eax

52f:89 45 f8 mov %eax,-0x8(%ebp)

c = !c;

532:66 83 7d f2 00 cmpw $0x0,-0xe(%ebp)

537:0f 94 c0 sete %al

53a:0f b6 c0 movzbl %al,%eax

53d:66 89 45 f2 mov %ax,-0xe(%ebp)

d = a&&b;

541:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

545:74 0d je 554

547:83 7d f8 00 cmpl $0x0,-0x8(%ebp)

54b:74 07 je 554

54d:b8 01 00 00 00 mov $0x1,%eax

552:eb 05 jmp 559

554:b8 00 00 00 00 mov $0x0,%eax

559:89 45 fc mov %eax,-0x4(%ebp)

d = a||b;

55c:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

560:75 06 jne 568

562:83 7d f8 00 cmpl $0x0,-0x8(%ebp)

566:74 07 je 56f

568:b8 01 00 00 00 mov $0x1,%eax

56d:eb 05 jmp 574

56f:b8 00 00 00 00 mov $0x0,%eax

574:89 45 fc mov %eax,-0x4(%ebp)

return;

机器指令逻辑非(!)实现的操作解释,以a = !a这个作为例子:

a = !a;

518:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

51c:0f 94 c0 sete %al

51f:0f b6 c0 movzbl %al,%eax

522:89 45 f4 mov %eax,-0xc(%ebp)

首先将变量a与常数0进行比较,如果相等就置寄存器al为1,不等则置为0,然后再把寄存器al的值扩展0扩展送到eax寄存器中,再从寄存器eax中送回到变量a的地址当中。

机器指令逻辑与(&&)实现的操作解释,以d = a&&b来解释。

d = a&&b;

541:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

545:74 0d je 554

547:83 7d f8 00 cmpl $0x0,-0x8(%ebp)

54b:74 07 je 554

54d:b8 01 00 00 00 mov $0x1,%eax

552:eb 05 jmp 559

554:b8 00 00 00 00 mov $0x0,%eax

559:89 45 fc mov %eax,-0x4(%ebp)

首先将变量a与0进行相比,如果变量a等于0,就跳到554这个位置,也就是执行指令mov $0x0,%eax,就是把0送到寄存器eax里面,再送到变量d当中。如果变量a不等于0,就用变量b与0相比,如果b等于0,也是跳转到554这个位置去将最终的结果设置为0,如果变量b也不等于0,就把1送到寄存器eax当中,将最终的结果设置为1。

机器指令逻辑或(||)实现的操作解释,以d = a||b来解释

d = a||b;

55c:83 7d f4 00 cmpl $0x0,-0xc(%ebp)

560:75 06 jne 568

562:83 7d f8 00 cmpl $0x0,-0x8(%ebp)

566:74 07 je 56f

568:b8 01 00 00 00 mov $0x1,%eax

56d:eb 05 jmp 574

56f:b8 00 00 00 00 mov $0x0,%eax

574:89 45 fc mov %eax,-0x4(%ebp)

首先将变量a与0进行相比,如果变量a不等于0,就跳转到558这个位置,也就是执行指令mov $0x1,%eax,把1送到寄存器eax里面,无条件转到574这个位置,并将eax的值送到变量d当中。如果变量a等于0,就将变量b与0比较,如果b等于0,就跳转到56f这个位置,去将最终的结果设置为0。

逻辑移位操作

C语言的移位操作包括逻辑左移,算术左移,逻辑右移,算术右移等四种。

操作

C语言操作符

汇编指令

逻辑左移

<<

shlb、shlw、shll

算术左移

<<

salb、salw、sall

逻辑右移

>>

shrb、shrw、shrl

算术右移

>>

sarb、sarw、sarl

注意:IA-32中的其他移位指令没有对应的C语言操作,如想实现循环移位指令,需要编写多条语句来实现。

逻辑移位和算术移位的C语言操作符相同,编译器会根据操作数的不同来选择不同的指令。无符号数采用逻辑移位指令,有符号数采用算术移位指令。逻辑和算术的区别在于友移时最高位补0还是补符号位。算术右移补入符号位,逻辑右移补入0。

我们仍然以一个简单的C语言指令来为大家介绍逻辑移位操作的汇编指令。

#include

void main()

{

int a = 0x80000000;

unsigned int b = 0x80000000;

short c = 0x8000;

unsigned short d = 0x8000;

a=a>>4;

b=b>>4;

a=c;

a=d;

b=c;

b=d;

return;

}

利用gcc命令将其进行编译,objdump命令进行反汇编之后,main函数所对应的汇编指令如下所示

000004ed :

#include

void main()

{

4ed:55 push %ebp

4ee:89 e5 mov %esp,%ebp

4f0:83 ec 10 sub $0x10,%esp

4f3:e8 46 00 00 00 call 53e <__x86.get_pc_thunk.ax>

4f8:05 e4 1a 00 00 add $0x1ae4,%eax

int a = 0x80000000;

4fd:c7 45 f8 00 00 00 80 movl $0x80000000,-0x8(%ebp)

unsigned int b = 0x80000000;

504:c7 45 fc 00 00 00 80 movl $0x80000000,-0x4(%ebp)

short c = 0x8000;

50b:66 c7 45 f4 00 80 movw $0x8000,-0xc(%ebp)

unsigned short d = 0x8000;

511:66 c7 45 f6 00 80 movw $0x8000,-0xa(%ebp)

a=a>>4;

517:c1 7d f8 04 sarl $0x4,-0x8(%ebp)

b=b>>4;

51b:c1 6d fc 04 shrl $0x4,-0x4(%ebp)

a=c;

51f:0f bf 45 f4 movswl -0xc(%ebp),%eax

523:89 45 f8 mov %eax,-0x8(%ebp)

a=d;

526:0f b7 45 f6 movzwl -0xa(%ebp),%eax

52a:89 45 f8 mov %eax,-0x8(%ebp)

b=c;

52d:0f bf 45 f4 movswl -0xc(%ebp),%eax

531:89 45 fc mov %eax,-0x4(%ebp)

b=d;

534:0f b7 45 f6 movzwl -0xa(%ebp),%eax

538:89 45 fc mov %eax,-0x4(%ebp)

return;

从sarl $0x4,-0x8(%ebp)这条指令可以清楚的看到当执行a右移4位的操作时,因为a是有符号数,所以执行的就是算术右移,对应的汇编指令sarl。而执行b右移时,因为b是无符号数,所以执行的是逻辑右移指令,对应汇编指令shrl。

a=c;

51f:0f bf 45 f4 movswl -0xc(%ebp),%eax

523:89 45 f8 mov %eax,-0x8(%ebp)

a=d;

526:0f b7 45 f6 movzwl -0xa(%ebp),%eax

52a:89 45 f8 mov %eax,-0x8(%ebp)

b=c;

52d:0f bf 45 f4 movswl -0xc(%ebp),%eax

531:89 45 fc mov %eax,-0x4(%ebp)

b=d;

534:0f b7 45 f6 movzwl -0xa(%ebp),%eax

538:89 45 fc mov %eax,-0x4(%ebp)

由这8条指令可以看出,在执行a=c的时候,执行的是符号扩展指令,z=d时执行的是零扩展指令,b=c时执行的是符号扩展指令,b=d时执行的是零扩展指令。因此我们可以看出,执行符号扩展还是零扩展是由等号右边的变量类型决定的,与等号左边的变量类型无关。

位运算的作用

可实现特定的功能:取特定位、保留特定位

周期短速度快:左移、右移可用于实现快速的整数乘、除法

可实现其他功能:原位交换

PS:交换变量a和变量b的值

普通方法

c = a; a = b; b = c;

位操作交换法

a = a^b; b = b^a; a = a^b;

位操作法原理:

b = b^(a^b) = b^a^b = b^b^a = a

a = (a^b)^(b^(a^b)) = a^b^b^a^b = b

以上内容就是本次我给大家分享的计算机系统基础学习的笔记-数据的位运算操作,小编也是初次入门,有什么地方写的不对的,还请多多指教。觉得还不错的点个赞支持一下小编,你的肯定就是小编前进的动力。另外如果想了解更多计算机专业的知识和技巧的,献上我的个人博客北徯,另外需要各种资料的童鞋,可以关注我的微信公众号北徯,免费的PPT模板,各种资料等你来领。

计算机AL教程笔记,计算机系统基础学习笔记(2)-数据的位运算操作相关推荐

  1. 【计算机专业漫谈】【计算机系统基础学习笔记】W1-计算机系统概述

    利用空档期时间学习一下计算机系统基础,以前对这些知识只停留在应试层面,今天终于能详细理解一下了.参考课程为南京大学袁春风老师的计算机系统基础MOOC,参考书籍也是袁老师的教材,这是我的听课+自查资料整 ...

  2. 计算机系统基础学习笔记(3)-浮点数的精度问题

    C语言中的浮点数,满足IEEE754标准,可表示带有小数的数值,C语言中的浮点数有精度限制,并不能表示所有的数. IEEE754单精度浮点数: 表示的数的10进制的有效位数只有7位,其中一位是符号位, ...

  3. python基础笔记_python基础学习笔记(九)

    python异常 python用异常对象(exception object)来表示异常情况.遇到错误后,会引发异常.如果异常对象并未被处理或捕捉,程序就会用所谓的 回溯(Traceback, 一种错误 ...

  4. 【AI教程】AI基础学习笔记(第3天)

    00. 目录 文章目录 00. 目录 01. 学习目标 02. 变换面板 03. 渐变网格 04. 宽度工具组 05. 封套扭曲 06. 混合工具 07. 路径编辑 08. 复合路径 09. 符号喷枪 ...

  5. Python【系列教程】之基础学习笔记

    一.python安装及第一个python程序 (1)官网下载最新版的python 64位安装包并进行安装 (2)配置环境变量 在安装的时候,直接勾选Add  Python 3.7 to Path,单击 ...

  6. 计算机系统基础学习笔记(7)-缓冲区溢出攻击实验

    缓冲区溢出攻击实验 实验介绍 实验任务 实验数据 目标程序 bufbomb 说明 bufbomb 程序接受下列命令行参数 目标程序bufbomb中函数之间的调用关系 缓冲区溢出理解 目标程序调用的ge ...

  7. 南京大学计算机实验教程,南京大学 计算机系统基础 课程实验 2018(PA0-1)

    申明,本人并非是南京大学的学生,此实验一共完成其中四部分,试验环境为Manjaro(并非PA0中间的docker) + SpaceVim, 此文为记录试验的部分心得. PA0 正如在本课程试验中间反复 ...

  8. python基础笔记_python基础学习笔记

    一.Python四种类型的数据格式 整数----2.3. 长整数:指的是比较大一点的整数 浮点数----3.23.52.3EE:标记表示10的幂. 复数----(-5+4J).(2.3-4.6J) 二 ...

  9. Java中大数据数组,Java基础学习笔记之数组详解

    摘要:这篇Java开发技术栏目下的"Java基础学习笔记之数组详解",介绍的技术点是"java基础学习笔记.基础学习笔记.Java基础.数组详解.学习笔记.Java&qu ...

最新文章

  1. IQueryable 和 IEnumerable
  2. update yum 到指定版本_linux yum安装指定版本mysql或php
  3. 【练习】2021下半年数据结构刷题笔记和总结 (三)栈 队列 链表 枚举算法
  4. mysql-nt.exe w3wp.exe cpu 100%_认识w3wp.exe进程,从根本上解决占用资源较大问题
  5. Java面试10大知识点总结宝典助你通关!已拿意向书!
  6. OpenWrt的UCI系统
  7. harbor 多端口_安装Harbor并修改默认使用的80端口
  8. crossentropy java_示例CrossEntropyLoss用于pytorch中的3D语义分段
  9. Axure 元件导入元件库
  10. 计算机硬盘容量的最小单位,计算机中存储数据的最小单位和存储容量的基本单位各是什么?...
  11. 电磁场理论笔记03:自由空间中微分形式电磁场定律和边界条件
  12. NY--234 -- 吃土豆 [二维动态规划]
  13. 什么是软件测试工程师呢?
  14. CSFB和SRVCC概念解释
  15. 第1节 基本数据类型分析
  16. 人头识别与计数_目标检测之人头检测(HaarLike Adaboost)---高密度环境下行人检测和统计...
  17. 主成分分析法的理解与人脸摆正实例
  18. smart-link monitor-link
  19. STC单片机使用Printf
  20. 编写一个留言簿程序,写入留言提交后显示留言内容

热门文章

  1. c++控制台下输出sin函数图形
  2. SharePoint的WebService的应用
  3. 中国科协、阿里云联合编纂云计算教材,为高校云计算人才培养注入强劲动力...
  4. setTimeout 定时器的使用
  5. 查询分页的几种Sql写法
  6. 设计模式学习笔记(十六:桥接模式)
  7. CSS 巧用 :before和:after
  8. win7如何打开防火墙某个端口的tcp连接
  9. OpenNI2下简单操作两个体感设备(Xtion与Kinect for Xbox 360)
  10. 云计算自动化对于虚拟化环境意味着什么?