CSAPP读书笔记


一、信息的表示和处理

1.信息存储

1)16进制表示法

1.选用16进制表示的原因
2.不同进制的转化
(1)形如 2的n次方 的十进制数转为十六进制:
在这里插入图片描述
(2)用辗转相除将十进制数转为十六进制数

2)字数据大小

32位程序和64位程序,主要的区别在于程序是如何编译的,而不是运行机器的类型。

3)寻址和字节顺序

1)大端法:
最高有效字节存储在最前面
2)小端法:(大多数Intel兼容机采用小端模式)
最低有效字节存储在最前面
【Arm支持双端法】

4)布尔代数

1)位级运算
(1)与 或 非 异或
(2)实现掩码运算
2)逻辑运算

3)位移运算
(1)左移:最右补0
(2)右移:
逻辑右移:最左补0(对无符号数大多是逻辑右移)
算术右移:最左补最高有效位(对有符号数大多是算术右移)

2.整数表示

1)无符号数和有符号数的表示:

1)对无符号数,8421码;
2)对有符号数,采用补码的形式表示;

2)无符号数和有符号数的转换:

1.c语言默认有符号数和无符号数比较时,都转为无符号数;
2.从一个较小的数据类型转换到一个较大的数据类型时:
a)对无符号数,零扩展;
b)对有符号数,进行符号位扩展;
3.较大的数据类型转换到一个较小的数据类型:
a)对无符号数,直接截断;
b)对有符号数,先直接截断得到最低的k位,再将截断得到的无符号数转化为有符号数。

3.整数运算

1)加法

(1)无符号加法:溢出

(2)补码加法:正溢出和负溢出
在这里插入图片描述

3)加法逆元(相反数):
对于无符号数:需要溢出来实现结果为0。
在这里插入图片描述

对于有符号数:
(a)若该值大于最小值,则加法逆元为该数的相反数;
(b)若该值等于最小值,也需要溢出实现,故其加法逆元为它本身。

2)乘除法

(1)对无符号数:相乘再截断
(2)对有符号数:相乘,截断,转为有符号数
(3)由于除法指令的执行需要多个时钟周期,很多编译器试图用移位,加法和减法来代替整数乘法的操作:
(a)乘以2的幂,用左移实现;
(b)除以2的幂,用右移实现;【无符号数(逻辑),有符号数(算术)】
(c)
c.1:x小于0时:
为符合整数除法向零舍入原则,需要在移位之前加入偏置(偏置的值为1左移k位减去1),通过加入偏置之后再进行算术右移,即可得到向零舍入的结果。
c.2:x大于等于0时:可直接进行算术右移。

4.浮点数

1)二进制小数

2)IEEE浮点表示

IEEE浮点表示

3)舍入操作

(a)向偶数舍入(向最近的值舍入):
在这里插入图片描述

(b)向零舍入:正数向下舍入,负数向上舍入;
(c)向下舍入:朝向小的方向舍入;
(d)向上舍入:朝向大的方向舍入;
向偶数舍入,避免了统计偏差。

4)浮点运算

(1)对浮点数的乘法和加法,不具有结合性。因为可能会有舍入。
(2)浮点乘法在加法上不具有分配性,也就是不能实现乘法分配律。

5)int、float、double 强制类型转换时

(1)int 转化为 float:可能会被舍入;
(2)int / float 转化为 double:可以保留精度的数值;
(2)double 转化为 float :可能会溢出或舍入;
(4)float / double 转化为 int:可能会向零舍入,可能溢出。

二、程序的机器级表示

1. 程序编码

1)机器级代码

对机器级编程来说,有两种抽象很重要:
第一种是由指令集体系结构或指令集架构来定义机器级程序的格式和行为,它定义了处理器状态、指令的格式,以及每条指令对状态的影响;
第二种是机器级程序使用的内存地址是虚拟地址,提供的内存模型看上去是一个非常大的字节数组。

2)寄存器(Register)

(1)整数寄存器
(a)包含16个命名的位置,用来存放整数数据与指针;
(b)调用者保存寄存器与被调用者保存寄存器
在这里插入图片描述
(2)条件码寄存器保存着最近执行的算术或逻辑指令的状态信息。
(3)各寄存器的作用:
(a)rax用来保存函数的返回值;
(b)rsp用来保存程序栈的结束位置;

3)汇编器与反汇编器

汇编器将汇编转化为机器代码,反汇编器反之。
下图中,左边为反汇编生成的汇编代码,右边为编译器直接产生的汇编代码。
在这里插入图片描述

2.访问信息

大多数指令包含操作码和操作数两部分。

1)操作数指示符

有立即数,寄存器和内存引用三部分。
立即数:形如 $8 为立即数;
内存引用:形如(%rax),即寄存器加了括号。
在这里插入图片描述

2)数据传输指令

最频繁使用的指令是将数据从一个位置复制到另一个位置的指令。
(a)MOV类指令:把数据从源位置复制到目的位置。
在这里插入图片描述
除此之外,64位的处理器有一条限制,即mov的源操作数和目的操作数不能都是内存的地址,该用如下方法:
在这里插入图片描述

3) 压入和弹出栈数据

栈的增长方向是从高地址到低地址,栈顶元素是所有栈中元素地址最低的。
栈是倒过来画的,栈顶在图中的底部,栈底在图中的顶部。
push 压栈
pop 出栈
在这里插入图片描述

3.算术和逻辑操作

1)加载有效地址

leaq(加载有效地址)
有效地址的计算方式与内存引用的计算方式一致;
leaq指令所执行的操作并不是去内存地址处读取数据,而是将有效地址的值直接写入到目的寄存器;
可以用来表示加法和有限的乘法。

2)一元和二元操作

(1)二元操作指令:包含两个操作数,第一个操作数是源操作数,第二个操作数既是源操作数又是目的操作数(不能是立即数)。
(2)一元操作指令:只有一个操作数,既是源又是目的。

3)移位操作

(1)左移:SAL SHL 补零
(2)右移:
SAR 算术 补符号位
SHR 逻辑 补零
(3)对于移位量k,可以是立即数或存放在寄存器中的值。(对于移位指令,只允许以特定的寄存器cl作为操作数)

4.控制

1)条件码

(1)条件码寄存器由CPU维护,长度是单个bit,描述最近执行操作的属性。
(2)常用的条件码:
a)CF(Carry Flag)—进位标志,当CPU最近执行的一条指令最高位产生了进位的时候,CF置1,可以用来检查无符号数是否溢出。
b)ZF(Zero Flag)—零标志,最近操作等于0是,置1。
c)SF(Sign Flag)—符号标志,最近操作结果小于0时,置1。
d)OF(Overflow Flag)—溢出标志,针对有符号数,最近操作导致正或负溢出时,置1。
(3)CMP
CMP S1,S2: 基于S2-S1,与sub不同,cmp只是设置条件码寄存器,并不更新目的寄存器的值;当a和b的值相等时,cmp会将零标志设置为1。
(4)TEST
TEST S1,S2: 基于S1&S2,与and不同,test只是设置条件码寄存器,并不更新目的寄存器的值;

2)访问条件码

条件码通常不会直接读取,常用的使用方法有三种:1)可以根据条件码的某种组合,将一个字节设置为0或1,2)可以条件跳转到程序的某个其他的部分,3)可以有条件的传送数据。
(1)SET指令:
属于第一种方法。他们区别在于考虑的条件码组合不同,不同条件码组合实现不同的效果,根据后缀体现。诸如sete(判断是否相等),setl(对有符号数判断是否小于),setb(对无符号数判断是否小于)等等。

3)跳转指令

根据条件寄存器的某种组合,或者跳转,或者继续执行代码序列中下一条指令。

4)用条件控制来实现条件分支

5)用条件传送来实现条件分支

控制的条件跳转在现代处理器上效率低,一种代替的策略是,用数据的条件转移。这种方法计算一个条件操作的两种结果,然后再根据条件是否满足从中选一个。只有在一些受限制的情况中,这种策略才可行。如果可行,就可以用一条简单的条件传送指令来实现他,条件传送指令更符合现代处理器的性能特性。

6)循环

循环语句是通过条件测试与跳转的结合来实现的。
(a)do-while
在这里插入图片描述

(b)while(与do-while在判断的顺序上不同)

(c)for
在这里插入图片描述

在这里插入图片描述

7)switch语句

在针对一个数据有多种可能的情况下时,switch语句有用,通过跳转表这种数据结构,使实现更加有效。跳转表是一个数组,每个元素都是一个指向代码位置的指针。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值