Posts 深入理解计算机系统笔记
Post
Cancel

深入理解计算机系统笔记

第1章:计算机系统漫游

程序的编译方式

  • 汇编阶段:汇编器将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o是一个二进制文件,它包含的17个字节是函数main的指令编码。
  • 链接阶段:printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器(ld)就负责处理这种合并。结果就得到hello文件,它是一个可执行的目标文件(或者简称为可执行文件),可以被加载到内存中,由系统执行。

处理器读并解释存储在内存中的指令

shell是一个命令解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果该命令行的第一个单词不是一个内置的shell命令,那么shel就会假设这是一个可执行文件的名字。

我们将处理器的指令集架构和处理器的微体系结构区分开来:指令集架构描述的是每条机器代码指令的效果;而微体系结构描述的是处理器实际上是如何实现的。

高速缓存至关重要

高速缓存存储器简称为cache,作为暂时的集结区域,存放处理器近期可能会需要的信息。高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。利用高速缓存的局部性原理。

文件是对IO设备的抽象表示,虚拟内存是对主存和磁盘IO设备的抽象表示,进程则是对处理器、主存和IO设备的抽象表示。

20世纪80年代中期,Unix厂商试图通过加入新的、往往不兼容的特性来使它们的程序与众不同,麻烦也随之而来了。为了阻止这种趋势,IEEE开始努力标准化Unix的开发,后来被命名为Posix。结果就得到了一系列的标准,称作Posix标准。

一些重要的主题

超线程:有时也被称为同时多线程,是一项允许一个CPU执行多个控制流的技术。它涉及CPU某些硬件有多个备份,比如程序计数器和寄存器文件,而其他的硬件部分只有一份,比如执行浮点算术运算的单元。举例来说,i7处理器可以让每个核执行两个线程,所以一个4核的系统实际上可以并行地执行8个线程。

超标量:如果处理器可以达到一个周期一条指令更快的执行速率,就称之为超标量处理器。

第2章:信息的表示和处理

信息存储

C编译器还把每个指针和类型信息联系在一起,这样就可以根据指针值的类型,生成不同的机器级代码来访问存储在指针所指向位置处的值。尽管C编译器维护着这个类型信息,但是它生成的实际机器级程序并不包含关于数据类型的信息。

ISO C99引入了一类数据类型,其数据大小是固定的,不随编译器和机器设置而变化。其中就有数据类型int32_t和int64_t,它们分别是4个字节和8个字节。使用确定大小的整数类型是程序员准确控制数据表示的最佳途径。

1
2
3
4
5
// 下面的声明都是同一个意思
unsigned long
unsigned long int
long unsigned
long unsigned int

小端法:小对小,大对大

大端法:反过来

字节大端小端方案或者说顺序会影响的情况:

  1. 网络传输过程中,大端机器和小端机器传送的时候字节会反序。
  2. 汇编代码中的数值表示
  3. 强制类型转换的时候

&符号是创建一个指针,指针包括地址信息还有类型信息。而强制类型转换不会改变真实的指针,它们只是告诉编译器以新的数据类型来看待被指向的数据。

布尔环:(a^b)^a=b就是布尔环,可以产生一些有意思的数学问题

位向量:a=[01101001]表示集合A={0,3,5,6},而位向量的应用之一就是集合->压缩?

移位运算:算术右移看开头,逻辑右移不看开头。机器基本都是逻辑右移。当移动k位的k过大的时候,需要对其取模,模“最大位数”。

关于数据类型转换,如补码反码等等、浮点数、定点数的知识都直接看书吧,这里整理起来太麻烦了,所以只会给出一些比较拓宽认知的小cases~

  • 对于大多数C语言的实现来说,类型转换从位的角度出发而不是从数学计算的角度出发。而强制类型转换的结果保持位的值不变,只是改变了解释这些位的方式。这就导致了处理同样字长的有符号和无符号数之间的转换规则时,数值可能会发生改变,但是具体的位不会发生改变
  • 无符号和有符号数字进行计算,无符号转换为有符号,然后假设两个数都是非负的,来执行这个运算
  • C语言标准中,short转化为int之后,再进行有无符号的转换即int->uint
  • 加减法其实是阿贝尔群的运算
  • 执行位级补码非的方法是:对每一位求补,再对结果加1
  • 将乘法运算替换为移位运算的方法是:比如用(a«1)+a来代替3*a
  • IEEE浮点数表达方式是比较标准且优美的表达方式,复杂但是好用。而由于相同的小数位数下,浮点表示方法不会很精确地等于你想要的数,因此,我们需要找到一个舍入方法将高精度数字(高精度的浮点数)舍入,这样就可以匹配到我们需要的那个数字,也就是匹配上我们需要的“次”精确值(次是相对于浮点数的)
  • 向偶数舍入方式:将数字向上或者向下舍入,使得结果的最低有效数字是偶数。选择偶数舍入的原因是可以抵消统计偏差,一般来说一半时间是向上舍入,剩下一半时间是向下舍入
  • C有库,一般定义INFINITY表示正无穷,而NAN表示Not a Number(NaN)
  • 必须小心地使用浮点运算,因为浮点运算只有有限的范围和精度,而且不遵守普遍的算术属性,比如结合性

第3章:程序的机器级表示

右移实现除法中的偏置量问题

问题的引出:

1
2
3
4
5
int div16(int x){
    int bias=(x>>31)&0xF;
    return (x+bias)>>4;

}

问题就在于代码中的第二行,当x>=0时,bias值为零,当x<0时,bias值为15。如果把这行注释掉,对于正数的计算结果是没有问题的,但是对于负数的计算结果,就比理论值小1(例如当x=-17的时候,结果为-2)。原因如下:

在计算机中,如果两个int型数a和b作除法(a/b),当a不能被b整除的时候,表达式的结果为(a/b)的商。这个商是通过向下取整得来的。即对于17/16,结果在区间(1,2)上,向下取整,得到1。考虑a<0的情况,当a=-17时,结果在(-2,-1)上,向下取整,得到-2。而我们期望的结果是-1。通过与偏置量相加,将结果偏移到(-1,0)上,再向下取整,就得到-1。

当不能整除时,计算机都会采取向下取整运算。对于正数,向下取整是符合我们习惯的,对于负数,我们的期望时绝对值向下取整,即整体向上取整,这与计算机的向下取整不符合,所以就要通过偏置量来实现。

关于偏置量的取值,当a>=0时,偏置量值为0;当a<0时,设偏移量为n,偏置量取值为(2^n-1)。

引用自CSDN:右移实现除法中的偏置量问题

This post is licensed under CC BY 4.0 by the author.

第十课:网络同步技术

第十一课:随机数在游戏中的应用

Trending Tags