Hello程序的一生

    科技2022-08-06  101

    Hello程序的一生

    一、孕育1、程序员行为2、计算机行为 二、出生  1、预处理  2、编译  3、汇编  4、链接 三、实现 “ 码 ” 生价值  1、启动 " 码 " 生  2、能量储备  3、释放能量 四、休眠五、死亡

    #include <stdio.h> int main(void) { printf("hello world\n"); return 0; } Hello程序

      hello程序作为C语言最经典的程序,虽然在实现上非常简单,无非就是在显示器上打印 " hello world " 几个字符,但是却需要计算机上几乎所有硬件设备以及操作系统、系统软件协同工作才能运行起来。

      近几年来,在软件工程师(特别是C语言工程师)的面试过程中,对于 “ hello程序是如何运行起来的 ” 之类 的面试题不断出现,由此,在这篇博文上将”对hello程序从诞生到死亡的各个阶段发生了什么,以及计算机是如何运行该程序进行详解。

      博文共分为五个部分,讲述了hello程序的一生,分别为:孕育、出生、实现 “ 码 ”生价值、休眠、死亡。

    一、孕育

    1、程序员行为

      从我们开始构思hello程序的功能开始,hello程序小生命的光辉一生便已开启,直到确定hello程序的功能是在显示器上显示 " hello world "这句话时,就像一颗受精卵 ( Idea ) 在温床上着陆。

      此时我们打开一个编辑器(类似Linux操作系统上的vim编辑器),将手放在键盘上,开始敲击键盘,按下脑子里所想的字符,直到代码完成,生成hello.c文件,此刻hello程序小生命的模样被勾勒完成,等待出生。

    2、计算机行为

      在这些过程中值得思考的是,我们写的hello.c代码文件(一般称为源文件)究竟是什么东西?计算机在这个过程中又做了哪些事情?

      首先,我们写的hello.c代码文件(一般称为源文件)究竟是什么东西?其实,我们写的源文件是一系列由0和1组成的位序列,8个位为一组,被称之为字节,而每个字节就是源文件上的每个字符,这些字符是由ASCII码表示的字符。因此,源文件被称之为文本文件,与之相对应的是二进制文件,文本文件与二进制文件的区别在于文本文件只能存放char型字符变量,而二进制文件能够存放char/int/float/double等等的数据。

      其次,计算机在这个过程中又做了哪些事情呢?为使大家能够更加清晰的理解计算机的运作过程,博主绘制了如下的计算机硬件系统图,并依据此图进行讲解。   计算机硬件系统主要由中央处理单元(CPU)、主存储器(主存)、总线、输入输出设备(I/O设备)组成,各个部分的功能如下:   1、中央处理单元(CPU)    简称处理器,它主要用作解释或执行主存中存储的指令。而处理器主要分为四个部分,分别是程序计数器(PC)、寄存器、算术/逻辑单元(ALU)、CPU对外总线接口。从系统上电开始,程序计数器便会指向主存中的某一条程序指令,处理器会不断地去处理执行PC指向的程序指令。当程序计数器指向某一条指令时,处理器会读取该指令,执行该指令表达的动作,然后更新PC,继续执行新的指令。寄存器是一个小的存储设备,是由一些一个字长的寄存器组成。ALU能够计算新的程序指令地址以及数据。CPU对外总线接口是CPU与外界通信的虚拟介质,对于 " 接口 " 这个概念,我们可以理解为插头与插座,CPU对外总线接口好比插座,外界的数据流好比插头,插头与插座相匹配才能信息往来。   2、主存储器(主存)    主存是一个临时存储设备,它的作用是存储程序指令以及程序处理的数据。它是一个掉电丢失的设备,当我们使用word等文本编辑器时,在没有保存文件时,文件里的数据都会存储在内存中,一旦计算机被断电,文件里的数据将会直接丢失!   3、总线    一种电子线管道,用于在计算机各个部分之间传递字节信息   4、输入输出设备(I/O设备)    能够与计算机系统建立连接的设备,是控制信号输入或信息输出的媒介。常见的输入输出设备包括鼠标、键盘、显示器等等。当然,只有输入输出设备是不足以和计算机成功建立连接,每个输入输出设备都需要有一个控制器或适配器与计算机连接(准确的说是与I/O总线进行连接)。

      在讲解好计算机硬件系统后,我们在计算机硬件系统的基础上看看我们敲下的字符都去哪了。   在上面这张图上我们可以看到1和2两条线路,这两条线路就是我们敲下的字符以及最后的源文件的成长路线。首先来看1号线路,在我们敲下某一个字符时,字符随着键盘到达USB控制器,后面便随着I/O总线一路奔向CPU,中途经过的I/O桥是外界数据流与CPU的月老,能够将两者牵上红绳,友好交流,随后,字符到达CPU对外总线接口,并流向寄存器,最终通过系统总线、内存总线到达主存,并随着一个个字符的输入,字符会在主存内按次序堆积。直到我们按下 " 保存文件 " 键,刚刚存放的所有字符便随着既定好的2号线涌向磁盘,存储在磁盘的某一块区域。

      至此,hello程序小生命的 " 码 " 生便来到了转折点,即将开启 " 码 " 生第二阶段:出生。

    二、出生

      在 " 十月怀胎 " 后,hello程序小生命将会出生,会面临四大阶段:预处理、编译、汇编、链接。这四个阶段的目的是为了将高级语言转换为为机器码,让计算机能够知道hello程序小生命的使命。

      1、预处理

        预处理器会根据 " # " 这个命令去修改源文件。hello程序第一行代码 " #include <stdio.h> " 告诉预处理器需要在当前位置包含 " stdio.h " 这个头文件的内容,因此,预处理器便查找该头文件,并将该头文件的内容完整的替换" #include <stdio.h> " 这句话。修改完成的源文件名变为 " hello.i "。

      2、编译

        编译器将修改过的源文件进行一次编译,生成 " hello.s " 文件,该文件是一个汇编程序文件。

      3、汇编

        汇编器将汇编程序文件再一次转换,转换为计算机能够看懂的机器码,机器码文件是由0或1组成的文件,也被称为可重定向目标文件,该文件(hello.o)实质上是一个二进制文件。如果我们用文本文件去查看该文件,则看到的将是一堆乱码。

      4、链接

        由于hello程序内使用了printf库函数,而printf库函数存放于单独编译好了的 " printf.o " 文件内,我们需要将 " printf.o " 文件与 " hello.o " 文件进行合并。整个代码需要正常运行还需要启动代码文件还能正常启动运行,因此,链接器将 " printf.o " 、" hello.o " 、启动代码文件进行链接,生成 " hello " 可执行目标文件,保存在硬盘里,该文件可以被直接加载运行。

      经过出生的四大阶段,我们的hello程序小生命已经诞生,接下来它将会经历成长,并实现它的 “码 ” 生价值。

    三、实现 “ 码 ” 生价值

      hello程序小生命的一生极其短暂,它的使命在它把 " hello world " 这句话显示在显示器上时便完成。下面我们来探索一下它的短暂 " 码 " 生。

      1、启动 " 码 " 生

        由于在windows的集成环境下启动hello程序使得hello程序小生命得一生被安排得明明白白,以至于我们无法一步步看清它的成长, 因此这里以Linux操作系统为例进行讲解,shell是Linux操作系统下的命令解释器,当shell的鼠标光标在闪烁时,提示我们输入命令,我们输入 " ./hello " 后,shell便会把从键盘输入的 " ./hello " 读入寄存器,存储在主存中。具体过程如下图1号线路。

      2、能量储备

        当我们输入 " ./hello " 后按下回车键,则shell便会执行命令,shell将使用一些指令将硬盘中存放的hello可执行文件程序指令以及数据复制到主存,为最终使命做准备。具体过程如下图2号线路。

      3、释放能量

        当主存中加载了hello程序指令以及数据时,处理器便会开始执行程序指令,最终,处理器将主存中存放的 " hello world\n " 字符复制到寄存器, 在经I/O总线流向显示器,在显示器中显示 " hello world " 。具体过程如下图3号线路。

    四、休眠

      当程序执行完后,hello程序积攒的能量被释放完,将进入休眠状态,它沉睡于硬盘的某个区域,等待唤醒(在shell中输入 " ./hello ")。当再次被唤醒时,它会再次储备能量并释放能量。

    五、死亡

      当我们将硬盘中的hello程序相关文件全部删除时,hello程序小生命的一生在此终结。

    Processed: 0.012, SQL: 8