程序从编译到被执行的流程
编译过程:源码编译生成可执行文件的过程
c语言的编译过程
c语言编译需要经过四个过程:
1、预处理:由c文件到i文件
2、编译:由i文件到s文件
3、汇编:由s文件到o文件
4、连接:有o文件到exe文件
编译一个小程序
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("hello world!\n");
return 0;
}
- 预处理:
预处理实际上是处理#的过程:#include 包含的头文件直接拷贝到hello.c中,#define定义的宏定义进行替换,同时删除代码中没有用的注释:
1、删除所有的#define,并展开所有的宏定义,说白了就是字符替换
2、处理所有的条件编译,#ifdef #ifndef #endif,
3、处理#include 将其指向的文件差插入到该行
4、删除注释
5、添加行号和文件标示,这样才能在调试和编译出错的时候知道是那个文件的哪一行
6、保留#pragma编译器指令,因为编译器需要使用
gcc -E hello.c -o a.c 可以生成预处理以后的文件,通过查看文件内容和文件大小可以得知a.c将stdio.h和stdlib.h包含了进来。
- 编译:编译的过程实际上是将高级的编程语言翻译成机器语言的过程
1、词法分析
2、语法分析
3、语义分析
4、优化后生成相应的汇编代码
gcc -S hello.c -o a.s 可以生成汇编代码
- 汇编:gcc -c hello.c -o a.o 是将源文件翻译成二进制文件,类Unix系统编译的结果生成.o文件,Windows系统生成的是.obj文件。所以,编译过程就是讲.c文件翻译成二进制文件。汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
- 连接:就像hello.c中使用到了C标准库的东西“printf”,但是编译过程只是将源文件翻译成二进制文件而已,这个二进制文件还不能直接执行,还需要一个动作:将翻译成的二进制文件与需要用到的库绑定在一块。
gcc hello.c -o a.out 可以生成可执行程序,即gcc不带任何参数。
内存分配:
预处理(Preprocessing):
预处理阶段主要处理源代码中的宏定义、文件包含、条件编译等指令。这个阶段并不会分配内存,它仅仅是文本替换的过程。
编译(Compilation):
编译阶段是将预处理后的源代码翻译成汇编语言或者直接生成机器代码。在这一阶段,编译器会进行语法分析、语义分析、中间代码生成、代码优化等操作。但编译阶段通常也不涉及内存分配,它主要关注的是代码的正确性和效率。
汇编(Assembly):
汇编阶段是将汇编语言代码转换成机器语言。在这一步,同样没有内存分配的操作,汇编器只是将汇编指令转换成对应的机器码。
链接(Linking):
链接阶段是将编译或汇编后生成的多个目标文件以及库文件合并成一个可执行文件。在链接过程中,链接器会确定各个模块的内存布局,为全局变量和静态变量分配内存空间
,并解决符号引用等。因此,内存的分配在链接阶段是静态分配的,主要是指针地址的确定。