CSAPP第二章札记(更新中)
信息的存储
二进制
起源悠久,可以追溯到埃及,印度巴拉巴拉,莱布尼茨进行了系统的发展,后由乔治·布尔进一步完善
相比十进制更容易表示,存储和传输,比如高电压表示1,低电压表示0
编码
无符号编码 大于等于零的数
补码 带正负号的整数
浮点数
信息存储和十六进制表示法
程序将内存看成一个很大的字节数组,称为虚拟内存
内存的每一个字节由唯一的数字来标识,称为它的地址
所有地址的集合,称为虚拟内存空间
在C语言中,我们可以通过指针引用数组元素,指针的值即某个对象的位置
1个字节(byte)或者说块,由8个位(bit)组成,一个位由0或1两种可能,最大是全部为1,即11111111;最小是0,即00000000。那么如果用十进制表示,最大值为255
字节作为计算机可寻址的最小单位,而并不是位
0x开头表示16进制(hex),具体的转换可以查询表格
字数据大小
字长
字(word),是CPU一次能处理的数据宽度单位
字长(Word Length),是字所用单位的大小,是CPU一次能处理字节(或位)的长度,也通常是一个寄存器的宽度。比如,32位系统可以一次处理字长为32位,即字4个字节的数据,64位系统可以一次处理字长为64位,即8个字节的数据
字长决定了虚拟地址最大的空间大小,最大为2的字长次方-1,程序最多访问2的字长次方大小的数据,如32位系统,虚拟内存空间的大小就是2的32次方个位,即4GB,64位系统为16EB
32位和64位程序的最大区别在于程序是如何编译的,而不是运行的机器类型,因为64位机器可以向下兼容32位,反之却不行,并且,这和操作系统,CPU等硬件都无关
数据类型

long即long int,表示长度更长的整数。所以我们通常用int就够了
寻址和字节顺序
对于多字节的程序对象,我们必须明确:
1.这个对象地址在哪里(如何寻址)
2.在内存中按什么顺序排列他们(字节顺序是什么)
不同的机器,从存储字节的顺序也不一样,主要有两种方式,大端序和小端序
大端序将最高有效字节置于更高的地址,小端序将最低有效字节置于更高的地址
这很好理解,我们取一个int类型的整数,值为0
x12345678,将它置于0x100地址处,int类型占四个字节,那么需要在内存里划分出0x100到0x103的内存大小,大端序下,12被置于0x100处,78被置于0x103处,小端序则相反,12被置于0x103处,78被置于0x100处
x86处理器采用小端序
网络传输一般采用大端序,也被称之为网络字节序,或网络序。IP协议中定义大端序为网络字节序
*关于字节顺序的后两种情况我其实没太看懂,分别是阅读表示整数数据的字节序列时字节顺序,当编写规避正常的类型系统的程序,这里先按下不表
表示字符串
C语言中,字符串被编译为以NULL结尾的字符数组
比如我们有一个abcde的字符串,在字符数组中实际上是a b c d e NULL长度为6个字节
NULL的十六进制表示为0x00,而字符串由ASCII字符编码,因此不需要考虑字节顺序,这就让文本数据比二进制数据有更强的平台独立性
布尔代数
布尔通过将逻辑值 TRUE(真)和
FALSE(假)编码为二进制值1和0, 设计出一种代数,以研究逻辑推理的基本原则

简单来说,就是
非¬
非0即为1,非非0即为0
与∧
全1为1,不全1为0
(只有两个条件中同时为真,结果才为真)
或∨
全0为0,不全0为1
(只要两个条件中有一个为真,结果就为真)
异或⊕
相同为0,不同为1
用集合理解和表示布尔运算
任取{76543210}
1:第n位是集合中的一个元素
0:反之
Not(非门)补集
And(与门)取交集
Or(或门)取并集
Xor(异或)对称差异
eg
01101001:{0356}
01010101:{0246}
not{1 3 5 7}
and:{0 6}
or;:{0 2 3 4 5 6}
xor {2 3 4 5}
C语言的运算
位级运算
C语言支持对每一个位进行布尔运算
| or
& and
~ not
^ xor
在位级运算中,先将十六进制转换为二进制进行运算,运算完再将二进制结果转换为十六进制结果
位级运算常用于掩码运算,比如子网掩码,这一块后面学到了再说
逻辑运算
逻辑运算符
|| OR
&& AND
! NOT
在C语言的逻辑运算中,所有非零参数均为1,而0依然表示false,最后仍返回1或0
比如:!0x114514,返回值为0x00
0x114514&&0x1234,返回值为0x01
0x114514||0x1234,返回值为0x00
移位运算
左移
把操作数x向左移k位,需要丢弃最高的k位置,并在右端补k个0(二进制中,最高位是最左边的位)
eg:01100011,左移2位为10001100
右移
右移分为逻辑右移和算术右移,逻辑右移和左移只是方向不同
算术右移需要特别注意。如果最高位是0,算术右移和逻辑右移相同,但如果最高位是1,那么最后需要补1,而不是0
对有符号数,几乎都使用算术右移,对无符号数,一定是逻辑右移
整数表示


通过查看32位和64位系统存储的整数范围,我们可以发现几个问题:
1.long类型在32位和64位下,存储范围存在明显差异
2.有符号整数的存储范围并不关于0对称,而是负数的范围比正数大1
我们一个一个来看这是为什么
1.由于C语言设计之初,电脑的字长多种多样,无法统一,于是C语言为了在不同机器上都能运行,只规定了各整数类型的大小顺序,这样,编译器可以根据机器的不同灵活调整
2 ≤ short ≤ int ≤ long ≤ long long
实际上,在16位机器的时代,int可以只占2个字节,但到了今天,在32位或者64位机器上则都占4字节,而最大的不同就是long和long long,C语言规定比int大就可以,所以在32位机器上和int一样占4字节,没有什么区别,但是在64位上占8个字节,存放数据的大小也变大了非常多
2.见下面的补码
不同数据的编码
无符号数的编码
这一块的内容书上说了很多,而且很晦涩,其实本质上是按权展开,即无符号表示的数值,就是它的二进制按权展开的结果
补码的编码
有符号数的表示方式为补码
假设有一个整数数据类型有w位,将最高位称为符号位,它具有负权重,权重为-2的w-1次方,符号位被设置为 1 时,表示值为负,而当设置为 0 时,值为非负
拿1 -1 5 -5举例

我们用0000 0000表示0,负数没有−0,而最小的 1000 0000被拿来表示−128,这就导致了负数比整数多一个的情况
| 符号 | 数量 |
|---|---|
| 负数 | 128 个(−128 ~ −1) |
| 0 | 1 个 |
| 正数 | 127 个(+1 ~ +127) |





