深入理解计算机系统(二):信息的表示和处理

深入理解计算机系统(二):信息的表示和处理

信息是怎样表示的?

​ 大多数计算机使用8位的块,或者字节,作为最小的可寻址的内存单位,而不是访问内存中单独的位。机器级程序将内存看作一个非常大的字节数组,成为虚拟内存,内存的每个字节都由一个唯一的数字来标识,成为它的地址,所有可能地址的集合就称为虚拟地址空间

十六进制表示法

​ ​ ​ ​ ​ ​ ​ 我们知道一个字节是由8位组成的,在二进制表示法中,范围为00000000 ~ 11111111。转化成十进制,值域就是0~255。这两种方式去描述位,都不太好,因为二进制太长,而十进制还要和二进制相互转换非常麻烦,于是想出了一个折中的方法——使用十六进制表示法。

​​ ​ ​ ​ ​ ​ ​ 下图展示了十六进制表示法对应的十进制和二进制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s5lZGU2A-1586855517914)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200414155530616.png)]

​ ​ ​ ​ ​ ​ ​ 以0x或者0X开头的数字就是16进制的值。关于十六进制、二进制、十进制之间的转换还是很基础的知识,一定要掌握,这里就不详细介绍啦!

字数据大小是什么

​​ ​ ​ ​ ​ ​ ​ 我们在下载某些软件安装包的时候,往往会看到32位和64位的安装包说明。这个32位和64位指的是啥呢?其实就是指32位字长机器和64位字长机器。
在这里插入图片描述
​​ ​ ​ ​ ​ ​ ​ 每台计算机都有一个字长,指明指针数据的标准大小。虚拟地址是以这样的一个字来编码的,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。比如说我的计算机字长是64位的,那么虚拟地址的范围就是0~2的64次方-1,程序最多访问2的64次方个字节。

​​ ​ ​ ​ ​ ​ ​ 大多数的64位计算机可以运行32位机器编译器的程序,但是64位的程序只能在64位机器上运行。

寻址和字节顺序

​ ​ ​ ​ ​ ​ ​ 在几乎所有的机器上,多字节对象被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。比如,类型为int的变量x的地址为0x100,即在C中地址表达式&x的值为0x100,那么x的4个字节将会被存储在内存的0x100、0x101、0x102、0x103位置。

​​ ​ ​ ​ ​ ​ ​ 那么具体怎么存放呢?有两种方式,一种是大端法:最高有效字节在最前面,还有一种是小端法:最低有效字节在最前面。还是以刚刚的例子说明,x的16进制值是0x01234567,地址范围0x100~0x103的字节顺序按照大端和小端法如下排列:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Tc8XUxh-1586855517916)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200414161338024.png)]

​​ ​ ​ ​ ​ ​ ​ 采用大端还是小端要看机器的类型,大多数是只用小端模式,也有新的微处理器采用双端法。

​ ​ ​ ​ ​ ​ ​ 对于我们来说,机器使用的字节顺序我们是无法见到的,但是字节顺序对于使用者来说确实很重要的。比如说,一台大端机器和一台小端机器进行网络通信,接收程序中会发现字里的字节是反序的。为了避免这样的问题,接受方就需要做出一些转换。

如何表示字符串和代码

​​ ​ ​ ​ ​ ​ ​ 字符串是由某个标准编码来表示,常见的是ASCⅡ字符码。在使用ASCⅡ码作为字符码的任何系统上都会得到相同的结果,和字节顺序、字大小规则无关。文本数据比二进制数据具有更强的平台独立性。

​ ​ ​ ​ ​ ​ ​ 怎么表示代码?在深入理解计算机系统(一)中我们简单介绍过,像hello.c这样的文件是用ASCⅡ字符构成的,属于文本文件,在编译后会生成字节表示的机器代码(二进制代码表示的)。即使是完全相同的进程运行在不同的操作系统上,会有不一样的编码规则。如下面这个sum函数,在不同操作系统上编译的结果存在差异:

int sum(int x,int y){
    return x+y;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TsP6WfWM-1586855517921)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200414170514072.png)]

C语言中的常见运算

布尔运算

​ ​ ​ ​ ​ ​ ​ 、&、|和^分别表示对应逻辑运算NOT、AND、OR、EXCLUSIVE-OR,具体的运算规则就不多介绍了。**、&、|形成了一个布尔代数**,布尔代数和整数算术运算有很多相似之处,比如布尔运算& 对|和|对&有分配律,比如a&(b|c)=(a&b)|(a&c),a|(b&c)=(a|b)&(a|c)。

​ ​ ​ ​ ​ ​ ​ 当考虑位向量上的~、&、 ^ 时,会得到一种不同的数学形式,称之为布尔环。有一个非常重要的性质,在刷算法题中可以运用它来解题,(a^ b)^a=b。

​​ ​ ​ ​ ​ ​ ​ 位向量还可以用来表示有限集合,又因为布尔运算|和&对应集合的并和交,~对应集合的补,所以用位向量表示集合时,可以非常方便求集合的交并补。

​​ ​ ​ ​ ​ ​ ​ 在C语言中是支持按位布尔运算的。

逻辑运算

​ ​ ​ ​ ​ ​ ​ 逻辑运算符||、&&和!,分别对应于命题逻辑中的OR、AND、NOT运算。逻辑运算和按位布尔运算是不同的:

  • 按位布尔运算只有在参数被限制为0或1的情况下,才和对应的逻辑运算有相同的行为。
  • &&和||与对应的&和|的第二个区别就是,如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。
移位运算

​ ​ ​ ​ ​ ​ ​ 移位运算无非是向左或者向右移动,以向右移动为例,一般有两种形式的右移:逻辑右移和算术右移。x>>k

​ ​ ​ ​ ​ ​ ​ 逻辑右移在左端补k个0,算术右移是在左端补k个最高有效位的值,举个例子如下图所示。斜体的数字表示的是左移/右移填充的值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NgyxCOmr-1586855517924)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200414164328504.png)]
​​ ​ ​ ​ ​ ​ ​ C没有明确规定对有符号数要有哪种形式的左右移,但是几乎所有的编译器/机器组合都用算术右移。在Java中,x>>k是算术右移,x>>>k是逻辑右移。

​​ ​ ​ ​ ​ ​ ​ 试想这样一个问题,一个数据类型是32位,但是我们移动的位数超过32会发生什么样的结果?比如对这个数据类型的变量左移40位。在C中,位移量是通过计算k mod w得到的,也就是说当w=32,k=40时,实际上会移动40%32=8位。

​ ​ ​ ​ ​ ​ ​ 如果在表达式中涉及加减法和移位运算要注意咯,加法和减法的优先级比移位运算要高,像1<<2+3<<4得到的结果是512而不是51(1<<2)+(3<<4)

如何表示整数

​​ ​ ​ ​ ​ ​ ​ 我们描述用位来编码整数时有两种不同的方式,一种只能表示非负数,一种能够表示负数、零和整数。

​​ ​ ​ ​ ​ ​ ​ C支持很多种整型数据类型,其中long的取值范围是唯一一个和机器相关的。在32位机器上long的范围是[-2147483648,2147483647],在64位机器上为[-9223372036854775808,9223372036854775807]。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ETcS1YJW-1586855517925)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200414165507967.png)]
​​ ​ ​ ​ ​ ​ ​ 我们可以看到取值范围是不对称的,负数的范围比整数大1,那么为啥会这样的?我们希望表示负数值是通过补码来实现的,有一半的位模式(符号位设置为1的数)去表示负数,而另一半(符号数设置为0的数)表示非负数,因为0也是非负数,所有这就意味着能表示的整数比负数少一个。

​ ​ ​ ​ ​ ​ ​ 在C中没有要求用补码去表示有符号整数,但是几乎所有的机器是这么做的。

发布了201 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40992982/article/details/105516288