程序环境和预处理

好久没写文章了这几天主要在学C++类和对象,快学完了,后面就写类和对象的文章,总的来说在学校自己学习的时间变得好少,好不习惯,然后今天想起来C语言还有一个很重要得知识点,今天刚刚复习了,就在写一篇文章自己也在来巩固一下。

  1. 程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境。

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。

第2种是执行环境,它用于实际执行代码。

我们在编译器上创建得源文件就是一个文本信息。也就是我们的源代码。

因为我们的机器只认识二进制,所以我们就要需要一个环境就是我们的翻译环境 。这个时候就会产生后缀为.exe这个可执行文件,然后运行环境就是执行我们的代码。

我们先写一个最简单的打印hehe这样的代码。然后点击生成可解决方案来到我们相应的路径下观看是否生成相应的文件。

这里我们就可以看到我们生成的test.c文件,我们的代码是

c 复制代码
#include<stdio.h>
int main()
{
	printf("hehe\n");
	return 0;
}

那我们上面说过这是一个文本信息,就是我们的源代码,我们也可以理解成我们写在编译器上的代码,我们查看的方式就是可以拿记事本将他打开。

我们这是可以看的懂得,然后我们的可执行文件是乱码,我们是看不懂这些东西的。

那我们今天学得这个就是详解编译和链接。

源文件要经过编译器变成可执行文件要进行编译和链接这两个步骤,但是编译链接里又有很多的细节,比如我们编译好是形成一个目标文件,我们VS下的编译器是通过cl.exe来形成后缀为.obj

的目标文件,我们的在经过VS的link.exe最后才生成可执行文件。

我们的编译也不是这么简单,要经过三个过程,那就是预处理,我们也可以称作为预编译,这里会形成一个test.i的文件,然后经过编译这个时候就可以形成一个后缀为.s的文件,最后来到我们的汇编才会形成test.obj文件。

我们就来详细讲解一下编译这些过程会发生什么事,因为小编的能力有限,如果大家想深入的了解这些,可以去看看一本书叫做《程序员的自我修养》这本书里面的汇编和和编译这个章节。

我们的在编译器上写出来的代码首先要经过文本操作,就是预编译,在这个环节种会处理#开头的,比如我们的头文件,还会处理注释,因为注释这个东西只是帮助我们程序员更好的理解,不能帮编译器做些事情,所有在这个过程中会被替换成空格还有就是一些宏定义,比如#define 会直接被替换,这个后面也会讲。

经过上面的一系列操作,最后变成我们的目标文件,每个源文件都会有对应得目标文件生成,但是我们要生成我们得可执行文件,程序才能运行起来,我们需要一个运行环境,这个时候,就得进行链接这个操作,才能得到我们得后缀为.exe的可执行文件。补充(在汇编这个过程还会生成符号表,以便于后面进行链接这个过程),什么是符号就是指我们写代码的全局变量,或者是函数名,编译器这个时候会给他们相应的地址,在链接的时候还会进行符号表的合并)声明和定义分离的时候。

上面这个图讲解了编译的过程,这里和大家说生成符号表是怎样的过程。


我们给的两个源文件经过编译这个过程生成test.obj and add.obj这两个目标文件,在add.c这个文件中ADD会给一个地址,假设就是0x100,但是在test.obj会对ADD和main都生成地址,这不同源文件下ADD的地址是不同的,这就是为什么我们后面链接的时候要进行合并,不过合并之后ADD的地址是定义中的,不是声明中的地址。

上面就是我们在链接过程会合并段表,就是在生成一个可执行文件,但是在链接这个过程中不只是合成段表,还会对我们的符号表进行合并和重定义。

因为小编的能力有限,知道这些知识,我们后面会对预编译也会进行讲解,但是今天的分享就到这里,我们下次再见。