计算机系统漫游

凡事预则立,不预则废。自本人购买深入理解计算机系统一书以来,4月有余。泛泛的浏览了一遍,但深感学习的不扎实。遂决定自今日始,写小文章记录自己对此书的学习过程。力求在接下来的工作和生活中,对此书能有一个略微扎实的掌握,不负自己的初心。

开篇作者讲述了通过学习计算机系统对自己编程有哪些帮助。举了如下的例子:

  1. 避免由计算机表示数字的方式引起奇怪的数字问题。
  2. 通过一些小窍门来优化自己的C代码,以充分利用现代处理器和存储器系统的设计。
  3. 了解编译器是如何实现过程调用的,以及如何利用这些知识来避免缓冲区溢出错误带来的安全漏洞。
  4. 学会如何编写自己的Unix shell、自己动态存储分配包、甚至于自己的Web服务器。
  5. 会认识并发带来的希望和陷阱。

一、引言
作者在介绍完学习这本书我们会有哪些收获后,开始了本章的第一部分内容,介绍了最经典的“Hello world”程序的完整生命周期,这对一个程序员了解自己编写的程序是很有帮助的。下面就对一个由C语言编写的Hello world程序进行描述:

程序示例代码如下

##############################################################################

#include <stdio.h>
int main()
{
printf(“hello, world\n”);
return 0;
}

#############################################################################
总的描述这个程序的执行过程为:

  1. 首先被程序员创建
  2. 到系统上运行
  3. 输出简单的消息
  4. 然后终止
    作者指明将沿着这个程序的生命周期,简要的介绍一些逐步出现的关键概念、专业术语、和组成部分

程序员首先用编辑器创建的Hello.c程序被称为源程序。源程序实际上是一个由0和1组成的位序列。8个位被组成为一组,称为字节。每个字节表示程序中的某些文本字符。这些文本字符在大多数的计算机系统上都是由ASCII标准表示的。有点需要注意的是:每个文本行都是以一个看不见的换行符‘\n’来结束的。有ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件。
作者在这里提出了一个基本的思想:系统中所有的信息————包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。


C编程语言的起源:
C语言是贝尔实验室的Dennis Ritchie于1969~1973年间创建的。后来C语言的标准化成了国际标注化组织的责任。这些标准定义了C语言和一些列函数库,即所谓的C标准库。Kernighan和Ritchie在他们的经典著作中描述了ASCII C。他们说到C语言是古怪的、有缺陷的、但同时也是一个巨大的成功。C语言主要有如下的三个特点:

* C语言与Unix系统关系密切。
* C语言小而简单
* C语言是为实践目的设计的。
C语言是系统级编程的首选,同时也非常的适用于应用级程序的编写。C语言的指针不易让人理解。同时,C语言缺乏对抽象的显示支持。例如类、对象和异常。

Hello.c程序的生命周期是从一个高级C语言程序开始的,因为这种形式能够被人读懂。但是呢、为了在系统上运行Hello.c程序,每条C语句都必须被其他程序转化为一系列的地低级机器语言指令。然后这些指令按照一种称为**可执行目标程序**的格式打包好,并以二进制磁盘文件的形式存放起来。目标程序也被称为**可执行目标文件**。
在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
linux> gcc -o hello hello.c
在这里,GCC编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello。这个翻译过程主要由四个阶段完成:

################################################################################

  1. 预处理阶段
    预处理器根据以字符#开头的命令,修改原始的C程序。得到Hello.i
  2. 编译阶段
    编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,他包含一个汇编语言程序。
  3. 汇编阶段
    汇编器(as)将hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中
  4. 链接阶段
    连接器(ld)负责将printf.o合并到hello.o程序中。最后得到hello文件,它是一个可执行目标文件,可以被加载到内存中,由系统执行
    #################################################################################

接下来作者告诉我们了解编译系统是如何工作的诸多好处

  • 优化程序性能
    一个switch语句是否比一系列的if-else语句高效? 一个函数调用的开销有多大?
    while循环比for循环更有效吗? 指针引用比数组索引更有效吗?
    *为什么将循环求和的结果放到一个本地变量中,会比将其放到一个通过引用传递过来的参数中,运行的更快?
  • 理解链接时出现的错误
    链接器报告说无法解析一个引用,这是什么意思? 静态变量和全局变量的区别是什么?
    静态库和动态库的区别是什么? 为什么有些链接错误直到运行时才会出现?
  • 避免安全漏洞

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