跳转至

主要介绍include和link

跑一个程序发生了什么

查阅资料的时候我发现就有一本书叫**《程序是怎样跑起来的》**,**在图灵图书社区**上也可以找到,这本书对计算机组成、原理都有一些比较普及性的讲解,刚入门的话我比较推荐。

队长让我主要介绍include和link那我就先介绍他们吧

让我们先写一个简单的代码:

简单的代码

将他保存到文件夹里然后用gcc指令对他进行编译:

gcc temp.c -o temp

gcc编译

这个指令会让gcc编译temp.c并生成一个叫temp的可执行文件,运行这个文件的效果就是输出"Hello,World"并输入一个字符。

但如果我们用一些文本软件(图中为gvim)打开生成的temp.exe,我们会看到

一堆乱码

将它转为**十六进制**后会变得好看一些(虽然还是看不懂

十六进制的乱码

这些乱码就是CPU的语言,即机器语言或者本地代码。

本地代码的内容是正常人类无法理解的,也正是因为如此,才有了用人类容易理解的C语言等编程语言来编写源代码,然后再将源代码转换成本地代码这一方法。

本地代码的内容是各种数值的罗列,我们在十六进制中看到的数值就是本地代码的真面目,每个数值都表示某一个命令或数据。在此我不打算更加深入,有兴趣的同学可以去了解一些汇编的知识。

而能够把C语言等高级编程语言编写的源代码转换成本地代码的程序就是编译器。每个编写源代码的编程语言都需要其专用的编译器。将C语言编写的源代码转换成本地代码的编译器称为C编译器。上面使用的gcc就是一种C编译器。

编译器生成本地代码通常有两个阶段:编译(compile)和**链接**(link):

编译和链接

编译生成的是.obj文件,也被称为**目标文件**,这种文件的内容是本地代码,但他并不能直接执行,原因是源代码中并没有记述其调用函数如 printf()和scanf()的具体内容。因此,这时就必须将存储着 printf() 和 scanf()的处理内容的目标文件同.obj文件结合,否则处理就不完整,EXE文件也就无法完成。我们如果在命令行下使用

gcc -c temp.c

也可以生成temp.o文件,这也是一种目标文件。

include的作用就是在编译的过程中将被include的文件的内容全部"复制"到include的指令处并参与编译。

而在编译后,把多个目标文件结合,生成1个.exe文件的处理就是链接运行连接的程序就称为**链接器**(linkage editor 或连结器)。

链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定向表,对其中记录的地址进行重定向(即加上该编译单元实际在可执行文件里的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实际的地址(也要加上拥有该符号定义的编译单元实际在可执行文件里的起始地址)。最后把所有的目标文件的内容写在各自的位置上,再作一些别的工作,一个可执行文件就出炉了。

简而言之就是连接器通过关联各个目标文件的地址,确保文件内的每个从外部调用的内容都有依据可循,从而生成一个可执行的.exe文件。

gcc中通过

gcc 1.o 2.o 3.o -o output

来链接三个目标文件生成一个可执行文件 output.exe。

(这只是一个比较粗糙的说法,编译的内容还有很多,不过因为这篇东西主要讲的是运行,我就不花太多篇幅在这上面,后面wiki里应该有讲CMake的文章,那里面介绍的应该会比较清楚:) )

点开一个.exe——CPU的日常工作

说到程序的运行就不得不提CPU,CPU负责的就是解释和运行程序,相当于计算机的大脑。CPU的内部由寄存器、控制器、运算器和时钟四个部分构成。

cpu的组成

当我们运行一个.exe文件时,这个文件会被复制到CPU的内存里,即计算机的主存储器(主存)内,然后才被运行。主存主要负责存储指令和数据,由可读写的元素构成。

主存内的每个字节都带有一个地址编号,CPU可以通过该地址读取主存中的指令和数据。

当我们运行一个程序的时候,cpu就通过不断地访问地址、获取数据来达到我们想要的效果

cpu运行一个程序

不管是多复杂的语法,对于CPU来说其实只有简单的4个指令,而编译的过程简单而言也就是把高级的语言分解为这4种基本的指令。

cpu指令