每一个Coder都是从”Hello,World”开始的。那么既然是修仙第一天,那我们就从”Hello,World”开始吧。
本文主要介绍一个简简单单的”Hello,World”程序是如何在计算机系统乃至网络跑起来的。(当然不会写的太复杂啦,毕竟这是一个漫长的过程)。
翠花,上代码:
1 | #include <stdio.h> |
信息就是位+上下文
hello程序的生命周期是从一个hello.c的源文件开始的。而源程序实际是一个由0、1组成的位(比特)序列,8位一组,称为字节。每个字节表示程序中的某些文本字节。大多数系统以ASCII码表示文本字符。例如以上代码就可以ASII表示为:
# | i | n | c | l | u | d | e | SP | < | s | t | d | i | o | . |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
35 | 105 | 110 | 99 | 108 | 117 | 100 | 101 | 32 | 60 | 115 | 116 | 100 | 105 | 111 | 46 |
h | > | \n | i | n | t | SP | m | a | i | n | ( | ) | { | \n | SP |
104 | 62 | 10 | 105 | 110 | 116 | 32 | 109 | 97 | 105 | 110 | 40 | 41 | 123 | 10 | 32 |
SP | SP | SP | p | r | i | n | t | f | ( | “ | H | e | l | l | o |
32 | 32 | 32 | 112 | 114 | 105 | 110 | 116 | 102 | 40 | 34 | 72 | 101 | 108 | 108 | 111 |
, | W | o | r | l | d | \ | n | “ | ) | ; | \n | SP | SP | SP | SP |
44 | 87 | 111 | 114 | 108 | 100 | 92 | 110 | 34 | 41 | 59 | 10 | 32 | 32 | 32 | 32 |
r | e | t | u | r | n | SP | 0 | ; | \n | } | |||||
114 | 101 | 116 | 117 | 114 | 110 | 32 | 48 | 59 | 10 | 125 |
hello.c是以字节序的方式存储在文件中的。系统中的所有信息(磁盘文件,用户信息,网络传输数据等)均由一串比特表示。区分不同数据对象的唯一方式是读这些数据对象时的上下文。比如不同的上下文中,一个同样的字节序列可能表示整数,浮点数,字符串或者机器指令。
程序到可执行文件的过程
预处理
cpp根据以字符#开头的命令,修改原始C程序。例如上例hello.c中#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h中的内容,并把它直接插入程序文本中。结果就得到了另一个C程序,通常是以.i作为文件扩展名。
编译
ccl将文本文件hello.i翻译成汇编语言hello.s
1 | main: |
汇编
as将hello.s翻译成机器语言指令,这些指令打包成hello.o中。
链接
hello程序调用了printf函数,存在于编译好的printf.o中,ld负责合并。它是一个可执行文件,可以被加载入内存,由系统执行。
理解编译系统的好处
- 优化程序性能。
- 理解链接时出现的错误。
- 避免安全漏洞。
硬件相关
Linux下,hello文件的执行过程如下:
1 | linux> ./hello |
第一行与第三行是shell,shell是一个命令行解释器,它输出一个提示符,等待输入一个命令。如果shell命令行第一个单词不是一个内置shell命令,那么shell会假设这是一个可执行文件的名字,它将加载并运行这个文件。所以上面案例shell加载并执行了当前目录下hello程序,然后等待程序终止。程序完成后,又切换回shell。
系统的硬件组成
- 总线:贯穿整个系统的是一组电子管道,即总线。携带信息负责在各个部件间传递。
- I/O设备:系统与外部的联系通道。
- 主存:临时存储设备,存储数据共处理器调用或修改。
- 处理器:执行存储在主存中指令的引擎。
运行hello程序
高速缓存
由上例可发现,系统花费了大量时间把信息从一个敌方搬到另一个地方。hello程序原本在磁盘上,加载时复制到主存,处理机运行时又由主存复杂到处理器。字符串原在主存上,后复制到内存,后复制到显示器。为了提高速度,便引入高速缓存。
操作系统管理硬件
当shell加载和运行hello程序时,以及hello输出消息时,并没直接访问键盘,磁盘或主存,而是通过操作系统。所以说我们可以理解操作系统是应用程序与硬件之间插入的一层软件。
操作系统通过进程,虚拟内存和文件来实现硬件与应用程序间的交互。
进程(处理器+主存+I/O设备)
虚拟内存(主存+I/O设备)
文件(I/O设备)