数据的表示和运算
分三个部分介绍
- 非数值数据的表示、数据的存储
- 数据宽度单位
- 硬件特征:大端/小端、对其存放
- 数值数据的表示
- 定点数的编码表示
- 整数的表示 (有符号和无符号)
- 浮点数的表示
- C语言程序的整数类型和浮点数类型
- 数据的运算
- 按位运算和逻辑运算
- 位移运算
- 位拓展和位截断运算
- 加减乘除
数据宽度表示
注意,在32位和64位机上,int
和pointer
的位宽是不一样的。
大端小端问题
存储的地址开始的地方是低字节
大端:低位数据存到高字节。(看起来和原来一样)
小端:低位数据存到低字节。(看起来作了反转)(IA32、x86-64都是小端)
只需要考虑指令中立即数的顺序。
对齐问题
Ailgnment:要求数据的地址是相应的地址边界。(宽度的整数倍)
整数编码
相关运算细节
当有符号和无符号同时出现时,将有符号转化为无符号。
不注明的情况下都表示有符号的!!!
注意sizeof
返回的是无符号整数类型!!!
Expanding, trucating
无符号拓展直接补0、截断直接截
有符号拓展复制符号位、截断直接截。有符号截断相当于取余
加减乘除
加减
无符号加法和有符号加法遵循同样的规则,都是用加法器完成
加法器根据Sub值做加法或减法,对结果不判定对错,生成标志位信息
标志位信息:
- ZF:零标志(Sum为0置1)
- SF:符号标志(与符号位相同)
- OF:溢出标志(有符号溢出)(AB同号,但与Sum不同号置1)
- CF:进/错位标志(无符号加溢出、减借位置1)
乘除
变量与常数的乘除可以用位移运算和加减运算代替。(除法结果永远是向下取整)
负数用位移代替除法时会出问题。需要做修正算法(目的就是让结果向上取整而不是向下取整,最终要达到向0取整的效果)
取负
取负操作、源码-补码、补码-源码永远是按位取反后加1。
Some C integer Puzzle
注意对于有符号的取反操作,一般是数值加负号,但最小值加取反仍是最小值。
浮点
目前所有计算机都支持IEEE(电器和电子工程师协会)浮点标准。
IEEE浮点标准用这个形式表示一个数 V = ( − 1 ) s × M × 2 E V = (-1)^s\times M\times 2^E V=(−1)s×M×2E
- 符号(sign)s决定一个数是正数还是负数
- 有效数(significand)M是一个二进制小数,小数域frac,n位
- 指数(exponent)E是2的幂,作用是对浮点数的加权,指数域exp,k位
名称 | 占字节数 | s | exp | frac |
---|---|---|---|---|
float | 4 | 1 | 8 | 23 |
double | 8 | 1 | 11 | 52 |
给定的位表示,根据exp的值,编码被分成3种不同的情况
- 规格化值 exp的位模式不全为1或全为0。
- 指数域解释为偏置形式:E = e - bias
- 其中e表示位模式二进制值,bias = 2^(k-1)-1
- 单精度范围:-126~127 双精度范围:-1022~1023
- 小数域定义为M = 1 + f
- f表示二进制位模式的值,M默认以1开头
- 指数域解释为偏置形式:E = e - bias
- 非规格化值 指数域全为0(用来表示非常接近0的数)
- 指数域解释E= 1 - bias,为实现平滑过渡
- 特殊数值 指数域全为1
- 小数域全为0时表示无穷
- 小数域非零时表示NaN,意思是不是一个数
舍入
采用向偶数舍入的方式,实际上提供了四种方案,这种最接近原始值
我们将最低位0认为是偶数,1认为是奇数。
浮点运算
浮点运算缺少重要的群属性(无结合性)
puzzle
int->float
会有精度损失int->double
不会有精度损失(只要int宽度小于53)!!
程序的机器级表示
暂时省略,更重实践而非理论
Linking
连接实现了模块化、高效化等。
本质就是将多个不同的可重定位目标文件的不同部分重组成一个大的可执行目标文件。
链接器的两个主要工作:符号解析、重定位
- 符号解析:将最终位置无法确定的符号(全局变量、函数)存入符号表中。
- 所有定义的符号的值就是其目标所在的首地址。
- 重定位
- 合并代码段和数据段(节)
- 将符号在
.o
文件中的相对位置重定位到可执行目标文件中的最终绝对位置。 - 更新所有的符号引用到它们的最新位置。
符号解析细节问题
当出现重名定义时,会有强弱之分。
强定义指初始化的定义。弱定义指没有初始化或者使用extern
前缀。
强定义只能出现一次,否则链接报错。
强弱定义都有时,使用强定义。只有多个若定义时,随机使用。
这里会有一些绕,容易出现一些问题。
牢记当强弱定义都有时,引用的永远是强定义的位置。
一种题型:链接报错--原因是强定义多次。
各种定义会导致的不同结果,可能出现的异常错误是符号解析的关键考点
重定位
三种可重定位的目标文件
- 可重定位
.o
- 可执行
.out
- 共享
.so
ELF文件格式
可重定位的目标文件和可执行目标文件的区别。(都是ELF格式)
举例一种相对地址重定位的工作过程
R_386_PC32:一种相对位置重定位值,以下是其计算过程。
填入的重定位值应该是实际跳转位置相对于 下一条指令(pc) 的位置。
执行时载入可执行文件
静态库
对于常用的函数,通常是创建静态库
.a
库文件
创建和链接
自建库并引入
着重理解过程!!!
静态库的使用
可重定位的目标文件的参数书写顺序很重要。
动态库,理解即可
过程
实例