前言
很多人做了很久的C/C++,也使用了很多的IDE,但很多人却不明白他们所写的.C文件在计算机底层怎么生成机器能够识别的二进制文件,这种变化经历了什么过程,这边文章将会对C语言编译的过程进行简述。
C程序编译步骤
C代码编程成可执行文件分为四步:
(1)预处理(2)编译(3)汇编(4)链接
预处理(生成.i文件)
-
头文件展开:带#的语句,就是预处理指令,预处理指令在执行预处理的时候就会被处理。例如#include<stdio.h>,stdio.h就是头文件,头文件在预处理阶段就会被拷贝到.C文件中,举一个很简单的例子,.h头文件中通常写的都是结构体的声明以及函数的声明,在预处理阶段机器会将这些声明全部拷贝到写好的.C文件中,此时.C文件就叫做预处理文件。
-
宏替换:在代码中用#define定义了一个宏,预处理阶段就会将这个预处理指令处理掉,将代码中所有调用宏的地方进行替换。
-
删除注释:在写代码中通常都会写很多注释://(单行注释),/* */(多行注释),这些注释都不是计算机要执行的,所以在预处理阶段都会被处理掉,不会写入预处理文件。
-
条件编译:在if后面加上合适的条件才会编译if和endif之间的代码,不通过则不会将代码写入预处理文件,也不会进行编译。#if 0 -> #endif(条件不成立,不会编译);#if 1 -> #endif(条件成立,不编译)。
-
添加行号和文件标识,这样在调试和编译出错的时候会知道是哪个文件的哪一行。
-
在预处理阶段不会检查代码语法的错误。
编译(生成.s文件)
- 将预处理文件编译生成汇编文件(了解,不对汇编做介绍)。
- 在编译阶段会对代码进行词法分析,语法分析,语义分析,说白了就是对代码的语法、变量定义是否合理等检查语法错误。
汇编(生成.o文件)
- 将生成的汇编文件编译生成计算机认识的二进制文件.o
链接
- 设置运行的环境,堆栈等,将程序依赖的库链接到最终的可执行文件当中。
- 举个例子:就像文件中使用了标准库中的函数"printf",但是编译过程只是把源文件翻译成二进制而已,这个二进制还不能直接执行,这个时候就需要做一个动作,将翻译成的二进制与需要用到库绑定在一块。打个比方编译的过程就向你对你老婆说,我要吃雪糕。你只是给你老婆发出了你要吃雪糕的诉求而已,但是雪糕还没有到。绑定就是说你要吃的雪糕你的老婆已经给你买了,你就非常happy。
结束
- 这就是C语言编译的整个流程:从高级语言-->汇编语言-->机器语言(机器只能识别二进制代码),从人能读懂看懂的代码编程计算机能识别运行的代码的过程。
gcc编译过程
gcc是C语言编译器,可以对文件进行分部编译,简单的看一下编译过程,更容易理解。
预处理:gcc -E hello.c -o hello.i
编 译:gcc -S hello.i -o hello.s
汇 编:gcc -c hello.s -o hello.o
链 接:gcc hello.o -o hello