编译和链接

  • 对于平常的应用程序的开发,我们一般都会使用一些流行的集成开发环境工具(IDE),比如Visual StudioXCodeAndroid StudioQT CreatorEclipse等等,这些IDE一般都会将编译和链接一步完成,通常把这一过程叫做构建。
  • 咱们写一个简单的helloworld.c程序,在linux下使用gcc编译,生成a.out的过程分解为4个步骤:预处理、编译、汇编、链接。
#include <stdio.h>

#define N 5

int main(void)
{
    printf("===%d====\n", N);

    return 0;
}

1、预编译

$ gcc -E helloworld.c -o helloworld.i

“-E”表示只进行预编译,只处理源代码中以”#”开头的预编译指令,如”#include”、”define”、”#if”、”#else”、”#ifndef”等等,处理规则如下:

  • 删除所有的注释(“//“和”/ /“)和所有的”#define”并展开所有的宏定义
  • 处理所有的条件编译指令(如:”#if”、”#ifdef”、”#elif”、”#else”、”#endif”)
  • 处理”#include”指令,将包含的文件插入到该指令位置,这是一个递归的过程,因为文件中可能还会包括其他文件
  • 添加行号和文件名标识,如 #2 “helloworld.c”,便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号
  • 保留所有的”#pragma”编译器指令,因为编译器要使用。

经过预编译后的”helloworld.i”文件不包含任何宏定义,所有的宏定义已经展开,并且包含的文件已经被插入到该文件中,所以当我们无法判断宏定义是否正常或头文件包含是否正确时,可以查看预编译后的文件来确定问题

2、编译

$ gcc -S helloworld.i -o helloworld.s

或者

$ gcc -S helloworld.c -o helloworld.s

编译过程就是把预处理完d额文件进行语法分析、词法分析、语义分析及优化后生成相应的汇编代码文件

3、汇编

$ gcc -c helloworld.s -o helloworld.o
$ gcc -c helloworld.c -o helloworld.o

也可以使用汇编器完成

$ as helloworld.s -o helloworld.o

经过预编译、编译和汇编后的”.o”文件,又叫目标文件

4、链接