基本概念
基础语法
gcc/g++ [选项] [源文件] [选项] [目标文件]
常用选项
基本选项
| 选项 | 作用 |
|---|---|
-o <file> | 指定输出文件名 |
-c | 只编译不链接,生成目标文件(.o) |
-E | 只进行预处理不编译 |
-S | 编译到汇编语言,不汇编 |
-v | 显示编译过程的详细信息 |
输出默认文件名
gcc main.c
- 没有
-o参数 - GCC默认会把可执行文件叫
a.out(这是Unix系统的传统名字)
输出指定文件名
gcc main.c -o main
gcc内部进行以下四个阶段
- 预处理:处理宏定义、头文件包含等
- 编译:将预处理后的文件编译成汇编代码
- 汇编:将汇编代码转换成机器码
- 链接:将目标文件链接成可执行文件
在链接完成后,中间文件会被删除掉
预处理
不指定文件名
gcc -E main.c
这会执行标准输出,将结果打印到屏幕上
指定文件名
gcc -E main.c -o main.i
main.i这个名字可以自定义,扩展名也可以自定义,比如.txt, .abc
常见约定
| 扩展名 | 含义 | 常用性 |
|---|---|---|
.i | 预处理后的C文件 | 最常用 |
.ii | 预处理后的C++文件 | 最常用 |
.txt | 文本文件 | 可用 |
| 无扩展名 | 任意文件名 | 不推荐 |
同理对于.s, .o文件也是一样的,这对于gcc来说是可以的,但对于make或其他通过扩展名判断文件类型的工具来说未必行得通
- 命令:GCC内部调用
cpp - 作用:
- 处理
#include-> 把头文件内容插入进来 - 处理宏定义
#define - 处理条件编译
#if/#ifdef
- 处理
- 输出一个扩展后的C文件
编译
gcc -S main.i -o main.s
- 预处理后的文件 -> GCC转换称汇编代码
- 这一步就是C -> 汇编
main.s是gcc编译阶段最后的人类可读的文件
汇编
gcc -c main.s -o main.o
- 汇编代码 -> 汇编器(
as) -> 目标文件.o .o文件是机器码二进制,基本不可读- 每个
.c文件都会生成一个.o文件
.o文件里有
- 函数的机器指令
- 数据段、符号表
- 调用其他库函数的信息
链接
gcc main.o -o main
- 链接器
ld会把.o文件,系统库(libc,libm等),其他.o问阿金,合并成最终的可执行文件main,这时printf等函数才真正找到实现
警告选项
| 选项 | 作用 |
|---|---|
-Wall | 显示所有常见警告 |
-Wextra | 显示额外警告 |
-Werror | 将警告视为错误 |
-w | 禁止所有警告 |
-pedantic | 遵循标准C,提醒非标准用法 |
GCC只会报真正严重的语法错误或链接错误
- 语法错误(如缺括号、括号不匹配)
- 类型错误(如
int *p = "abc";) - 链接错误(如调用不存在的函数)
但像初始化、隐式转换、可能丢失精度等警告,默认不报
GCC设计之初遵循“兼容老代码”原则,C语言历史上很多老程序有未初始化、隐式转换等现象,默认警告太多导致就代码编译报满屏,用户体验很差
因此,开发中推荐的做法是
gcc -Wall -Wextra -Werror main.c
这样可以保证代码更安全、更规范,尤其是底层/库开发、游戏引擎开发、嵌入式开发等
-Wall
开启常用警告,比如
- 未使用的函数或变量
- 不匹配的格式化字符串(
printf/scanf) - 可能的类型转换问题
但不会开启一些“更严格的检查”
-Wextra
常见警告示例
| 类型 | 示例代码 | 警告 |
|---|---|---|
| 未使用参数 | int f(int x){return 0;} | unused parameter 'x' |
| 空函数体 | void f(){} | empty body (depends) |
| 不完全初始化数组 | int arr[5] = {1,2}; | missing initializer for element 2 |
| 多余的逗号 | int arr[] = {1,2,}; | extra comma |
隐式int转换 | char c = 200; | oveerflow in implicit constant conversion |
return没有值 | int f(){} | control reaches end of non-void function |
不同版本GCC会有差异
优化选项
| 选项 | 作用 |
|---|---|
-O0 | 不优化(默认) |
-O1 | 基本优化 |
-O2 | 进一步优化(推荐) |
-O3 | 最高级别优化 |
-Os | 优化代码大小 |
调试选项
| 选项 | 作用 |
|---|---|
-g | 生成调试信息 |
-ggdb | 生成GDB专用的调试信息 |
-pg | 生成性能分析信息 |
语言标准选项
-std
gcc -std=c99 file.c
- c99
- c11
- gnu99
- c++11
- c++20
使用示例
基本编译
# 编译单个文件
gcc main.c -o main
g++ main.cpp -o main
# 编译并运行
gcc main.c -o main && ./main
多文件编译
# 方式1:直接编译多个文件
gcc file1.c file2.c file3.c -o program
# 方式2:分步编译(适合大型项目)
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc file1.o file2.o -o program
链接库文件
# 链接数学库
gcc program.c -o program -lm
# 链接pthread线程库
g++ program.cpp -o program -lpthread
# 指定库路径
g++ program.cpp -o program -L/path/to/lib -lmylib
包含头文件
# 添加头文件搜索路径
g++ program.cpp -o program -I/path/to/include
编译过程
gcc/g++编译分为四个阶段