本文主要介绍gcc编译c语言过程,以及常用命令
文章目录
- C语言编译过程
- 1. 预处理(Preprocessing):
- 2. 编译(Compiling):
- 3. 汇编(Assembling):
- 4. 链接(Linking):
- 实例
- GCC 编译命令
- 编译选项:
- 链接选项:
- 其他选项:
C语言编译过程
C语言编译过程是将源代码转换为可执行程序的过程,包括预处理、编译、汇编和链接四个主要阶段。以下是对每个阶段的详细介绍:
1. 预处理(Preprocessing):
- 在这个阶段,首先对源文件进行预处理。预处理器根据源文件中的指令,如#include、#define等,展开宏定义,处理条件编译指令,以及包含头文件等。
- 预处理器的输出结果是一个经过预处理的中间文件,通常以.i作为文件扩展名。
2. 编译(Compiling):
- 经过预处理的中间文件被送入编译器进行编译,编译器将源代码翻译成相应的汇编代码。
- 这个阶段主要包括词法分析、语法分析、语义分析和优化等步骤。编译器会对语法进行检查,并生成相应的汇编语言文件。这个阶段的输出通常是以.s作为文件扩展名的汇编语言文件。
3. 汇编(Assembling):
- 汇编器将汇编代码转换成目标文件,目标文件包含了可重定位的机器码。
- 汇编器将汇编语言文件转换为机器语言文件,通常以.o作为文件扩展名的目标文件。
- 在汇编阶段,汇编器将汇编代码转换为机器码指令。每一条汇编指令对应一条机器码指令,并生成目标文件。目标文件是一种二进制格式文件,其中包含了机器指令和数据。
4. 链接(Linking):
- 链接器将目标文件与所需的库文件进行链接,生成最终的可执行文件。
- 在链接过程中,链接器会进行符号解析、重定位和地址空间分配等工作,以确保各个模块之间能正确地连接起来。
- 最终生成的可执行文件可以在计算机上直接运行。
链接的作用主要有以下几个方面:
-
符号解析:在编译过程中,源代码中的函数和变量可能会被定义在不同的源文件中或外部库中。链接器负责解析这些符号引用,并将其与相应的定义关联起来,确保所有的符号引用都能正确地找到对应的定义。
-
重定位:编译器生成的目标文件中,包含了相对于源代码中的符号位置的地址偏移量。链接器负责将这些相对地址转换为绝对地址,并将不同目标文件中的代码和数据按照正确的偏移量进行合并,以生成最终的可执行文件。
-
库文件链接:在编译过程中,经常会使用到各种库文件,包括系统提供的标准库和第三方库。链接器会将目标文件与这些库文件进行链接,以解析并满足对库函数的引用。
链接的过程可以分为两种类型:静态链接和动态链接。
-
静态链接:库文件可以是静态库(.a 或 .lib),静态链接器会将目标文件和库文件的代码和数据合并到一个单独的可执行文件中。在运行时,所有的代码和数据都被复制到内存中,程序独立运行,不再依赖于外部的库文件。静态链接生成的可执行文件相对较大,但具有更好的独立性和可移植性。
-
动态链接:动态库(.so 或 .dll),动态链接器将目标文件生成一个可执行文件,但并不将所有的库代码和数据都合并进去,而是在程序运行时再去加载所需的动态链接库。这样可以减小可执行文件的大小,并且多个程序可以共享同一个动态链接库的实例,减少内存占用。动态链接需要在运行时保证所需的动态链接库存在于系统中。
实例
下面以hello world实例为例子:
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
- 预处理:
- 预处理阶段展开头文件和宏定义。
- 我们可以使用以下命令进行预处理:gcc -E main.c -o main.i
- 运行命令后会生成一个经过预处理的中间文件main.i,其中包含了main.c中所有的头文件和宏定义的展开内容。
gcc -E main.c -o main.i
- 编译
gcc -S main.i -o main.s
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 14, 0 sdk_version 14, 0
.globl _main ; -- Begin function main
.p2align 2
_main: ; @main
.cfi_startproc
; %bb.0:
sub sp, sp, #32
.cfi_def_cfa_offset 32
stp x29, x30, [sp, #16] ; 16-byte Folded Spill
add x29, sp, #16
.cfi_def_cfa w29, 16
.cfi_offset w30, -8
.cfi_offset w29, -16
mov w8, #0
str w8, [sp, #8] ; 4-byte Folded Spill
stur wzr, [x29, #-4]
adrp x0, l_.str@PAGE
add x0, x0, l_.str@PAGEOFF
bl _printf
ldr w0, [sp, #8] ; 4-byte Folded Reload
ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
add sp, sp, #32
ret
.cfi_endproc
; -- End function
.section __TEXT,__cstring,cstring_literals
l_.str: ; @.str
.asciz "hello world\n"
.subsections_via_symbols
- 汇编
汇编阶段将汇编代码转换成目标文件
gcc -c main.s -o main.o
- 链接
链接阶段将目标文件与库文件链接,生成可执行文件。
运行命令后会生成一个名为myprogram的可执行文件,其中包含了main.o和helper.o的机器码,并链接了所需的库文件。
gcc main.o helper.o -o myprogram
GCC 编译命令
gcc 是 GNU Compiler Collection 的缩写,它是一个功能强大的编译器套件,支持多种编程语言,包括 C、C++、Objective-C、Fortran、Ada 等。下面是 gcc 命令的一些常用选项和参数的详细解析:
编译选项:
-
-c
:只编译不链接,生成目标文件(.o 文件)。
示例:gcc -c hello.c -
-E
:只进行预处理,不进行编译和链接,将预处理结果输出到标准输出。
示例:gcc -E hello.c -
-I<include_path>
:添加头文件搜索路径。
示例:gcc -I/usr/local/include hello.c -
-D<macro>
:定义预处理宏,相当于 #define 指令。
示例:gcc -DDEBUG hello.c -
-O<level>
:指定编译优化级别,其中 可以是 0、1、2 或 3,分别表示不优化、基本优化、更多优化、最大优化。
示例:gcc -O2 hello.c
链接选项:
-
-o <output_file>
:指定输出的文件名,即生成的可执行文件的名称。
示例:gcc hello.o -o hello -
-L<library_path>
:添加库文件搜索路径。
示例:gcc -L/usr/local/lib hello.o -o hello -
-l<library_name>
:链接指定的库文件。
示例:gcc hello.o -lmylib -o hello -
-static
:静态链接所有库文件,生成静态可执行文件。
示例:gcc hello.o -static -o hello -
-shared
:生成共享库(动态链接库)。
示例:gcc -shared hello.o -o libhello.so -
-fPIC
:生成位置无关的代码,用于共享库的编译。
示例:gcc -fPIC -c hello.c
其他选项:
-
-g
:在可执行文件中加入调试信息,以便进行程序调试和跟踪。
示例:gcc -g hello.c -o hello -
-Wall
:开启所有常见的警告信息,有助于发现潜在的代码问题。
示例:gcc -Wall hello.c -o hello -
-std=<standard>
:指定使用的语言标准,如 -std=c11 表示使用 C11 标准。
示例:gcc -std=c11 hello.c -o hello -
-pthread
:添加对 POSIX 线程的支持。
示例:gcc -pthread hello.c -o hello -
-M
:生成依赖关系,用于 Makefile 的自动生成。
示例:gcc -M hello.c > hello.d
参考链接:
- https://blog.csdn.net/qq_42570601/article/details/121261526
- http://blog.chinaunix.net/uid-26212859-id-3774650.html
- https://blog.csdn.net/weixin_42307601/article/details/128853010