信息的存储

二进制

起源悠久,可以追溯到埃及,印度巴拉巴拉,莱布尼茨进行了系统的发展,后由乔治·布尔进一步完善

相比十进制更容易表示,存储和传输,比如高电压表示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)