前言:
最近挖的坑太多了,导致有两三周都没有更新博客和github了。第一个坑就是这本《深入理解计算机系统》,第二个坑是Python,第三个坑就是机器学习了。最近两周每一部分都在学习,不停的转换,想总结总结,感觉都已经一团乱麻了,于是就有了这么一篇流水账的博客吧。
我的github:
我实现的代码全部贴在我的github中,欢迎大家去参观。
https://github.com/YinWenAtBIT
第一章:
计算机系统漫游:
一、程序被其他程序翻译的过程:
这个过程就是程序从文本编译成可执行的目标程序的过程了。本科的时候学习从来没有仔细探究过这个过程。编程的时候也遇上了不少编译链接的问题。是时候好好解决它了。
1. 预处理阶段:这个阶段,预处理器根据#开头的命令来修改原始的C/C++程序。比如把头文件插入到程序文本中,还有预定义的替换等等,然后就会得到另一个C程序,通常以.i文件扩展
2. 编译阶段:这个过程,编译器吧.i文件翻译为文本文件.s,这是一个汇编程序的文本文件,如果汇编学的足够好的话,是可以根据发现之前的C和这个汇编程序的对应关系的。后面的学习中,也让我彻底明白了C是如何变成汇编的。
3.汇编阶段:汇编器将.s文件翻译成.o文件,这是机器语言的指令,是一个二进制文件,到这一步其实还可以使用objdump命令进行反汇编,可以得到.s文件。
4. 链接阶段:程序调用的各个函数.o文件通过特定的方式和我们编译好的.o文件进行合并,有连接器来完成这个工作 ,然后得到可执行的目标文件。链接阶段在后面还会详细的学习
二、计算机体系结构
在这里我只讲讲处理器里的部分,其他的部分太熟悉了。
CPU:由PC(程序计数器),寄存器,ALU(算数逻辑单元),总线接口组成
ALU是做计算的,这个不多说,总线和寄存器就不说了,来仔细说说PC这个东西。
以前学习的时候,总是不明白PC到底怎么用的,直到彻底了解了程序运行时候的几个存储空间之后,才弄得清清楚楚。
首先,代码段,数据段,堆区,栈区。基本就这几个区。都放在内存中,但是他们的地址都是互相独立开来的,也就说没有重叠。PC指向的就是保存下一个指令代码的地址。
并且这个地址,会在程序调用的时候被压栈,就是返回地址,同样就是程序调用的下一条语句的地址。这么基本上把它们的关系说清楚了,不清楚的可以找《CSAPP》仔细读读。
第二章:
信息的表示和处理:
一、信息储存:
这里涉及到的二进制,八进制,十六进制就不罗嗦了,大家都懂,大端模式小端模式,找找资料也明白,这里写一写大家平时不太容易注意的问题。
首先是机器码:不同的机器类型,操作系统会有不同而且不兼容的指令以及编码的方式,同一个程序编码出来的二进制文件是不同的,所以说这就是为什么二进制的程序不能在不同的操作系统上移植 了。
算数右移与逻辑右移:算数右移是带符号位的,逻辑右移不带,几乎所有的编译器和机器都对有符号的数默认使用算数右移。所以大家不用纠结这个问题了。
数字截断:比如64位的long变成32为的int,并且有符号和无符号怎么处理呢?
答案是:别想那么多,高位扔掉啦,剩下的位直接当做unsigned int或者int,看你转换成什么了。才不给你保存符号位
二、数字运算:
无符号加法溢出:超过了减去2^k,判断是否溢出,只需要满足 s<x 或者s<y,因为x+Y>=x。
补码加法溢出:负的变成正的,正的变成负的,想想就明白了
补码的非:最小的负数的非是它本身,因为取非的过程是找一个加法逆元,满足x+(-x)=0,而最小的负数,自身相加溢出得0。其他的数的非都是正常的加一个负号。或者直接按照各位取反加一,结果还是溢出变成了最小的负数
补码的乘法溢出:别想那么多,计算的方式是正常的乘法,截断方式和无符号数一样,高位扔了,剩下是什么就是什么。
补码除以2的幂:这里有一个隐含的问题,是向上取整还是向下取整,如果对于正数:7/2=3.5=3,向下取整无所谓。但是负数就不能向下取整了-7/2=-3.5=-3。如果直接使用右移,那么会得到-4,因为右移是向下取整的过程。
解决的办法是:
x<0?(x+(1<<k) -1): x) >>k
做一个补偿,x/y向上取整等于(x+y-1)/y向下取整。
浮点数:
这个非常麻烦,但是仔细读一读就明白了:分成符号,尾数,阶码三个部分。
其中根据阶码有:规格化的,非规格化的,无穷大与NaN几个不同的区别。
浮点运算:
这里有一部分需要特别注意:
1.不具有结合性:
因为浮点数表示范围的原因,一个很大的数和一个很小的数相加,小数可能被忽略。所以如果改变顺序,小数可能就消失了。
总结:
《CSAPP》这本书确实能解决很多以前一直烦恼的问题,值得一读,问题就是讲的太详细了,太长了,得找一个方法加速阅读才行。