一个C程序最后生成可执行目标文件,会分阶段经过预处理, 编译, 链接的过程,而往往整个过程由IDE提供的编译驱动程序, 全权代表用户调用预处理器,编译器,汇编器和链接器。
预处理
// test.c
#include <stdio.h>
#define pai 3
// this is conment
int main()
{
Element i = 10;
Element result = pai * 3;
printf("%d\n", result);
}
gcc -E test.cpp > test.i
-E 选项调用预处理器cpp, 默认是输出预处理后的信息至屏幕上, 所以需要重定向至文件, 打印test.i的信息是:
......还有头文件等信息已经省略
typedef int Element;
int main()
{
Element i = 10;
Element result = 3 * i;
printf("%d\n", result);
}
发现其实预处理器在这里只干了3件事:
- 去掉注释
- 宏替换
- 复制头文件
链接
链接器在软件开发中很重要, 正是因为它的, 使得分离编译成为可能.
- main.c
#include <stdio.h>
extern num1;
int main()
{
int num2 = 10;
printf("%d + %d = %d\n", num1, num2, add(num1, num2));
}
- foo.c
int num1 = 20;
int add(int num1, int num2)
{
return num1 + num2;
}
gcc -c main.c -o main.o 生成可重定位目标文件main.o
gcc -c foo.c -o foo.o 生成可重定位目标文件foo.o
gcc main.o foo.o -o a.out 链接多个可重定位目标文件生成可执行目标文件
整个过程如图所示:
静态链接.jpg
从以上过程可以明白链接器的主要作用是链接多个目标文件成为一个可执行文件。
附 gcc编译命令
// test.c
#include <stdio.h>
int main(int argc, char **argv)
{
printf("hello world\n");
}
- 预处理
gcc -E test.c -o test.i
- 编译生成汇编代码
gcc -S test.i -o test.s
- 汇编器生成可重定位目标文件
gcc -c test.s -o test.o
- 链接器生成可执行目标文件
gcc test.o -o test.out
- 显示警告
gcc -Wall main.c -o a.out
- 保留中间文件
gcc -save-temps main.c -o a.out
- 链接动态库
gcc main.c -o c.out -l pthread
- 定义宏
#include <stdio.h>
int main(int argc, char **argv)
{
#ifdef MARCO
printf("MARCO defined\n");
#endif
}
gcc -DMARCO="hello" main.c
输出:MARCO defined
网友评论