我们就明确一个事实:即不论是嵌入式系统,亦或是普通PC电脑,对于程序的运行硬件处理器只能识别0/1的二进制码。从类人语言的C代码,需要经过一系列的转换过程,才能完全翻译成机器识别的0/1二进制码流。
总的来说,从C语言代码翻译为二进制的过程,主要经历以下四个阶段:
阶段一:预编译
阶段二:编译
阶段三:汇编
阶段四:链接

  1. 【预编译】
    预编译,看一个预字,就表明它是正式编译前的准备阶段。在C语言的代码中,预编译阶段主要完成下面几个工作:
    头文件展开:我们常看到每个C文件的第一行都是#include形式,该形式表明对头文件的引用。源代码开始进行编译之前,这些include(被包含进来的)的文件需要在#include的位置进行展开。
  2. C语言 运行reboot c语言 运行时_预编译

  3. 宏替换:在C语言中,一些常用的变量,比如圆周率可以使用C语言的宏定义方式进行常量级别的定义。与头文件展开一样,宏定义也是在引用的位置进行变量展开。宏定义的方式为:#define 标识符 字符串
    例如我们定义:#define Max_length 1000
    条件编译:即我们可以让编译器根据我们设定的条件,让符合条件的代码参与编译,不符合条件的代码不参与编译。以此来实现我们对最后目标代码的控制(不参与编译的代码,实现的功能不会进入到目标代码中)。
  4. 编译,根据字面理解,就是对指定的C语言代码进行“翻译”的过程,并根据C语言中我们前面讲到的各种语法规则,在编译器的参与下,生成符合指定运行硬件的汇编代码。
    我们都明确,目标代码是要运行在硬件上,不管你是ARM,MIPS还是X86。每个不同的硬件,存在不同的汇编指令,编译的过程是要从C语言生成汇编指令,所以不同的硬件都会由其厂家或者其他编译器开发公司,提供符合对应硬件的编译器。我们常见的有X86下的GCC,ARM下的arm_cc和MIPS下的mips_gcc。
  5. 【汇编】
    汇编,一句话概括就是完成上一个阶段生成的汇编代码转换机器码。这个阶段,非底层的程序员不需要考虑, 编译器不会搞错的。也与c/c++开发者无关,但是我们可以利用反汇编来调试代码。
  6. 【链接】:
    C语言的源文件经过了预编译,编译和汇编,都已经转化为了目标文件。我们在代码开发过程中,引用的一些C语言前辈们开发的库文件也是以成型的目标文件的形式给出的。但是这些零散的二进制文件,彼此之间是零散分布的,需要一种方式将它们有机的结合在一起,形成一个可运行的统一的目标文件。那么这个过程,就是链接器的主要工作。
    关于链接中的动态库静态库问题。大家可以简单的理解为:静态库经过链接过程,会被打包进最后的可执行文件a.out文件;动态库只有在a.out文件正式开始运行的时候,才会载入到内存,参与运行。所以,静态链接后,a.out文件的大小往往大于动态链接后的a.out文件大小。
  7. C语言 运行reboot c语言 运行时_宏定义_02

  8. 在visual studio中 通过编译和链接这两个步骤之后将会在文件中产生一个.exe可执行文件。这个可执行文件是由VS(C语言编译工具)软件生成的。当单击“执行”或者按下快键键Ctrl+F5时,执行的就是这个.exe文件。但是这个文件并不是由VS执行的,而是由CPU执行的。
    当单击“执行”按钮时,VS编译工具就会向操作系统发出请求,让操作系统执行.exe文件。而操作系统收到VS的请求时,就会调用CPU。执行的结果就是在显示器上输出,这就是此程序执行的过程。