编译过程:
- 预处理:预处理器将对源文件中的宏进行展开。
- 编译:编译器gcc将c文件编译成汇编文件。
- 汇编:汇编器as将汇编文件编译成机器码。
- 链接:将目标文件和外部符号进行连接,得到一个可执行二进制文件。
以一个很简单的01_test.c来探讨这个过程。
#include <stdio.h>
#define NUMBER (1 + 2)
int main(void)
{
int x = NUMBER;
printf("x:%d\n",x);
return 0;
}
- 预处理
[csy@local compile_test]$ gcc -E -o 01_test.i 01_test.c
用cat查看01_test.i的内容如下:
int main(void)
{
int x = (1 + 2);
printf("x:%d\n",x);
return 0;
}
可以看到,文件中宏定义NUMBER出现的位置被(1+2)替换掉了,其它的内容保持不变。
2. 编译成汇编代码
gcc -S -o 01_test.s 01_test.i
通过cat test.s查看01_test.s的内容为汇编代码。
[csy@local compile_test]$ cat 01_test.s
.file "01_test.c"
.section .rodata
.LC0:
.string "x:%d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $3, 28(%esp)
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
.section .note.GNU-stack,"",@progbits
- 使用汇编器编译成机器码
[csy@local compile_test]$ gcc -c -o 01_test.o 01_test.s
生成的机器码:
ELF ? 4 ( U夊冧饍?荄$ ? 婽$塗$?$椟? 擅 x:%d
GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4) .symtab .strtab .shstrtab .rel.text .data .bss .rodata .comment .note.GNU-stack 4 - X % d + d 0 d 8 0 j - A ? ? Q ? ?
@ ? - 01_test.c main printf "
- 使用链接器把目标文件链接成可执行文件
将所有的 .o文件链接起来生成可执行程序。
[root@zhifachen test]# gcc -o 01_test.exe 01_test.o
运行:
[csy@local compile_test]$ ./01_test.exe
x:3
编译过程小结
预处理阶段:对包含的头文件(#include)和宏定义(#define、#ifdef等)进行处理
gcc -E-o 01_test.c 01_test.i
//-o表示输出为指定文件类型 -E将源文件(.c)转换为(.i)
编译阶段:检查代码规范性、语法错误等,在检查无误后把代码翻译成汇编语言
gcc -S -o 01_test.i 01_test.s
//-S将已预处理的C原始程序(.i)转换为(.s)
汇编阶段:
gcc -c -o 01_test.o 01_test.s
//将汇编代码编译成机器码
链接阶段:将目标文件整合起来链接为可执行程序
gcc -o 01_test.exe 01_test.o
//将机器码(.o)和一些库函数整合成(.exe)
gcc常用选项
快速编译示例:
预编译,生成已预编译过的C原始程序*.i
gcc -E gcc_test.c -o gcc_test.i
编译,生成汇编语言原始程序*.s
gcc -S gcc_test.i -o gcc_test.s
编译,生成目标文件*.o
gcc -c -o 01_test.o 01_test.s
链接,生成可执行程序
gcc -o 01_test.exe 01_test.o
方法二:
编译
gcc -c gcc_test.c -o gcc_test.o
链接
gcc -o gcc_test.exe gcc_test.o
运行测试程序
./gcc_test.exe
方法三:
编译并链接
gcc -o gcc_test.exe gcc_test.c
运行测试程序
[csy@local compile_gcc]# ./gcc_test.exe
MAX=100
max(3,4)=4
编译时候传递全局宏定义示例
在代码中可以直接使用#define 来定义一个宏,然后在代码中引用,有时候我们希望通过编译时候决定编译宏内容,以及宏是否定义,这时候可以通过编译时候 -D 选项来指定。
hello.c源码
#include <stdio.h>
int main(void)
{
#ifdef CSY//表示如果定义了CSY,即命令行参数传了CSY,就执行下面的输出
printf("CSY is defined!\n");
#else
printf("CSY is not defined!\n");
#endif
printf("main exit\n");
return 0;
}
条件编译,用-D传递,如果没有传CSY则执行#else
[csy@local compile_gcc]# gcc -o hello hello.c -DCSY
[csy@local compile_gcc]# ./hello.exe
CSY is defined!
main exit