CSAPP第二章(上)
十六进制表示法
用十进制表示二进制比较麻烦,所以人们通常用十六进制来表示二进制
可以记住ACF三个十六进制数字对应的二进制数字的数值来推算BDE
A: 0X1010
C: 0X1100
F: 0X1111
2^n和十六进制的转换
2^n == 1后面n个零
n = i + 4j
转换为十六进制就是0X(2^i)(j个零)
比如对于2^11
i = 3
j = 2
转换为十六进制就是0X800
十进制数转换为十六进制数字
辗转相除法
实质就是0X?????是十进制数转换成的十六进制数字,每次对16取余,得到的就是右移一位被抛弃的数字,最后合起来就是原数
十六进制数转换为十进制数字(无符号数)
从低位向高位依次乘以20到2n-1(n为位数)
十六进制数转换为十进制数字(有符号数)
计算机中对于有符号数字的编码采用补码的形式
最高位代表负权重
从低位向次高位依次乘以20到2n-2,最高位乘以2^n-1
64位字长和32位字长
字长:总线一次传输可以传输的位数。
字长指明了指针数据的标准大小。
大多数64位机器都可以运行32位的程序,这是一种向后兼容。
对于32位的程序和64位的程序主要的区别是程序是如何编译的
gcc -m32 -o hello32 hello.c
gcc -m64 -o hello64 hello.c
大端法和小端法
intel小端,IBM和SUN为大端(大多数)新的处理器很多支持双端法
大端:低位地址存放权值大的数字
小端:低位地址存放权值小的数字
代码区分在p67
左移和右移
左移:往左移动一位,最右面补0
逻辑右移:往右移动一位,最左边补0(无符号数)
算数右移:往右移动一位,如果最高位是1,就在最高位补1(有符号数)
数的存储方式
无符号数和有符号数
有符号数最高位表示负权重
无符号数的最大值:2^(n)-1
有符号数的最小值:-2^(n-1)
1000 0.....
有符号数的最大值:2^(n-1) -1
0111 1.....
无符号数和有符号数之间的转换
无符号数和有符号数位模式没有改变但是解释这些数的方式改变了。
有符号数转为无符号数:
- 当最高位为0时,直接转换
- 当最高位为1时,
无符号数转换为有符号数
- 当最高数值为0时候,直接转换
- 当最高数值为1时候,该数减去2^n就是转换过去的数值
有符号数和无符号数计算时,有符号数会隐式转换为无符号数来进行计算
无符号小变量转换为无符号大变量
在拓展的位直接补充零
有符号小变量转换为有符号大变量
符号位为0,直接补0
符号位为1,直接补1
不管多少位,全为1都表示-1,所以负数前面补充1不会改变大小
有符号小变量转换为有符号大变量
直接截断,然后变为想要的位数。
这种转换会改变原有数值
数的运算
溢出
unsigned char a = 1;
unsigned char b = 255;
unsigned char c = a+b;
a+b超过了uchar的最大值,发生了溢出
此时c = 0;
无符号数的加法
0000 0001 + 1111 1111 = 1 0000 0000 = 0000 0000;
此时超过了uchar的界限,要把最前面的1消去,相当于减去2^n
当发生溢出后,无符号数相加的结果小于其中任何一个数。
有符号数的加法
正溢出:要减去2^n
0111 1111 + 0000 0001 = 1000 0000;
负溢出:要加上2^n
1111 1111 + 1000 0001 = 1 0111 1111 = 0111 1111;
当两个正数相加得到的结果为负数,或者当两个负数相加得到的结果为整数就发生了溢出
加法逆元
两个数相加为0(相反数?)
无符号数的加法逆元:两个数相加为2^n
1-1 = 1+254
有符号数的加法逆元:
-2^n<= x <= 2^n-1
- 当该数不是最小数值,直接符号位取反
- 当该数是最小数值的时候,加法逆元就是本身
乘法
任何一个二进制数乘以2^n就是让这个二进制数左移n位然后补充0
二进制数乘一个普通的数转换成二进制数乘以2^n之间进行的加法
除法
对于无符号数除以一个2^n就是逻辑右移
对于有符号数除以一个2^n就是算数右移
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号