一、GCC简介:
gcc的原名叫做GNU C语言 编译器(GNU C Compile),只能编译C语言程序,后来很快就做了扩展,支持了更多的编程语言,比如C+ Object-c ...,改名为GNC 编译器 套件(GNU Compile Collection) 支持很多的硬件和操作系统。
二、编译过程
C语言的编译过程可分为四个阶段:预处理->>编译->>汇编->>链接
下面以hello.c为示例详细介绍各个编译过程:
//示例hello.c #include <stdio.h> int main (void) { printf ("hello world! "); return 0; }
1、预处理
预编译过程主要处理那些源代码中以#开始的预编译指令,主要处理规则如下:
1)将所有的#define删除,并且展开所有的宏定义;
2)处理所有条件编译指令,如#if,#ifdef等;
3)处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。
4)删除所有的注释//和 /**/;
5)添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;
6)保留所有的#pragma编译器指令,因为编译器须要使用它们;
gcc -E hello.c -o hello.i
得到一个.i为后缀的预处理之后的文件,该文件叫做预处理文件,以下为预处理后的输出文件hello.i的内容:
# 1 "hello.c" # 1 "<built-in>" # 1 "<命令行>" # 1 "hello.c" # 1 "/usr/include/stdio.h" 1 3 4 # 28 "/usr/include/stdio.h" 3 4 /***** 省略了部分内容,包括stdio.h中的一些声明及定义 *****/ # 2 "hello.c" 2 int main (void) { printf ("hello world! "); return 0; }
2、编译
编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件。
gcc -S hello.i -o hello.s
得到一个.s为后缀的汇编文件,以下为编译后的输出文件hello.s的内容:
.file "hello.c" .section .rodata .LC0: .string "hello world!" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp movl $.LC0, (%esp) call puts movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3" .section .note.GNU-stack,"",@progbits
3、汇编
汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。
汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
gcc –c hello.s –o hello.o
得到一个.o为后缀的目标文件,由于hello.o的内容为机器码,不能以文本形式方便的呈现。可用命令hexdump hello.o 打开。
4、链接
目标代码不能直接执行,要想将目标代码变成可执行程序,还需要进行链接操作。
才会生成真正可以执行的可执行程序。链接操作最重要的步骤就是将函数库中相应的代码组合到目标文件中。
gcc hello.o -o hello
实现链接的处理,默认生成可执行文件 a.out,可以通过 -o来指定输出文件名。
三、文件名后缀
文件名后缀 |
文件类型 |
.c |
C源文件 |
.C .cpp .cc .c++ .cxx |
C++源文件 |
.h |
头文件 |
.i |
预处理后的C源文件 |
.s |
汇编程序文件 |
.o |
目标文件 |
.a |
静态链接库 |
.so |
动态链接库 |
原文链接:
https://blog.csdn.net/qq_29350001/article/details/53339861