一、C 语言编译器 GCC:开启编程之旅
1.1 GCC 安装:一站式工具链
GCC(GNU Compiler Collection)是 Linux 下最常用的 C/C++ 编译器,支持多种编程语言。安装命令(适用于 Debian/Ubuntu 系统):
sudo apt-get install build-essential
build-essential 包包含 GCC、G++、make 等开发工具,一次安装即可满足基本编译需求。
1.2 GCC 基础使用:从源码到可执行文件
编译单个 C 文件
# 默认生成 a.out 可执行文件(推荐显式指定输出名)
gcc main.c
# 显式指定输出文件名(更规范)
gcc main.c -o main # 生成 main 可执行文件(Linux 下无需 .exe 后缀)
gcc main.c -o main.exe # 也可添加 .exe 后缀(兼容 Windows 习惯)
运行可执行文件
# 当前目录执行(需加 ./ 表示当前路径)
./main # 执行当前目录的 main 文件
/home/user/main # 执行绝对路径下的文件
1.3 编译四步法:深入理解编译过程
C 程序的编译分为 预处理、编译、汇编、链接 四个阶段,GCC 可通过选项控制每个阶段。
1. 预处理(Preprocessing)
- 作用:处理 #include 头文件、#define 宏定义等。
- 命令:
gcc -E main.c -o main.i # 生成预处理后的文本文件 main.i(无宏和头文件展开)
2. 编译(Compilation)
- 作用:将预处理后的代码转为汇编语言。
- 命令:
gcc -S main.i -o main.s # 生成汇编文件 main.s(内容为人类可读的汇编代码)
3. 汇编(Assembly)
- 作用:将汇编语言转为二进制目标文件(.o)。
- 命令:
gcc -c main.s -o main.o # 或直接对 .c 文件执行:gcc -c main.c -o main.o
4. 链接(Linking)
- 作用:将多个目标文件和库文件链接为可执行文件。
- 命令:
gcc main.o -o main # 链接单个目标文件
gcc file1.o file2.o -o program # 链接多个目标文件
1.4 实战作业:用 GCC 编译冒泡排序并调试
第一步:用 Vim 编写冒泡排序代码(bubble.c)
#include <stdio.h>
void bubble_sort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr)/sizeof(arr[0]);
bubble_sort(arr, n);
printf("排序后的数组:");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
第二步:编译并运行
gcc bubble.c -o bubble # 编译为可执行文件
./bubble # 运行结果:11 12 22 25 34 64 90
第三步:用 GDB 调试(需安装 gdb)
sudo apt install gdb # 安装调试器
gdb bubble # 启动 GDB 调试
(gdb) break main # 在 main 函数入口打断点
(gdb) run # 运行程序,停在断点处
(gdb) next # 单步执行(跳过函数调用)
(gdb) step # 单步执行(进入函数内部)
(gdb) print arr # 打印数组内容
(gdb) quit # 退出调试
二、C++ 编译器 G++:支持现代编程范式
G++ 是 GCC 用于编译 C++ 代码的前端,使用方法与 GCC 类似,但会自动链接 C++ 标准库。
2.1 安装与基本使用
# 通常随 build-essential 安装,若未安装:
sudo apt install g++
# 编译 C++ 文件(.cpp 或 .cxx)
g++ main.cpp -o main # 生成 C++ 可执行文件
2.2 C++ 特性支持
- C++11 及以上标准:需添加 -std=c++11 选项(如 g++ main.cpp -o main -std=c++11)。
- 链接 C++ 库:G++ 会自动链接 libstdc++,无需手动指定。
三、Linux 库开发:动态库与静态库详解
3.1 动态库(Shared Library):运行时加载
概述
- 特点:程序运行时动态加载,多个程序可共享,节省内存,更新方便(无需重新编译程序)。
- 命名规则:lib库名.so(如 libadd.so,库名为 add)。
创建与使用步骤
- 编写库代码(add.c):
int add(int a, int b) { return a + b; } // 保存为 add.c
- 编译为动态库:
gcc -shared -fPIC add.c -o libadd.so # -shared 表示生成动态库,-fPIC 生成位置无关代码
- 编写调用程序(main.c):
#include <stdio.h>
extern int add(int a, int b); // 声明外部函数
int main() {
printf("1 + 2 = %d\n", add(1, 2));
return 0;
}
- 编译时指定库路径(两种方式):
# 方式一:直接指定库文件路径(适合临时使用)
gcc main.c ./libadd.so -o main
# 方式二:通过 -l 选项指定库名(需将库放到系统搜索路径,见下文)
gcc main.c -ladd -o main # -ladd 对应 libadd.so
- 运行时找不到库的解决方法:
-
- 方法一:复制到系统库目录(不推荐,可能污染系统):
sudo cp libadd.so /lib/ # 系统库目录
sudo cp libadd.so /usr/lib/ # 用户库目录
-
- 方法二:添加自定义库路径到系统搜索列表:
-
-
- 创建个人库目录:mkdir ~/mylib
-
-
-
- 复制库到该目录:cp libadd.so ~/mylib
-
-
-
- 编辑系统库配置文件:
-
sudo vim /etc/ld.so.conf # 添加一行:/home/用户名/mylib
sudo ldconfig # 刷新库缓存
3.2 静态库(Static Library):编译时链接
概述
- 特点:库代码在编译时直接嵌入可执行文件,运行时无需依赖库文件,体积较大,更新需重新编译程序。
- 命名规则:lib库名.a(如 libadd.a,库名为 add)。
创建与使用步骤
- 编译目标文件:
gcc -c add.c -o add.o # 生成 add.o 目标文件
- 打包为静态库:
ar -r libadd.a add.o # -r 表示替换或添加文件到库
- 编写调用程序(同动态库的 main.c):无需 extern 声明,直接编译链接:
gcc main.c libadd.a -o main # 直接指定静态库文件
- 执行:
./main # 输出:1 + 2 = 3(无需依赖库文件)
四、编译器与库对比:选择合适的工具
类型 | 优点 | 缺点 | 适用场景 |
GCC/G++ | 跨平台、支持多语言 | 需命令行操作(新手需适应) | 所有 C/C++ 开发 |
动态库 | 节省内存、更新方便 | 运行时依赖库文件 | 大型项目、共享库开发 |
静态库 | 独立可执行、无需依赖 | 体积大、更新麻烦 | 小型项目、嵌入式开发 |
五、总结:从编译到部署的完整流程
- 新手入门:先用 GCC 编译简单 C 程序,掌握 -o、-c 等基础选项。
- 进阶学习:理解编译四阶段,学会用 GDB 调试代码,解决编译错误(如头文件缺失、链接失败)。
- 库开发:从动态库开始,掌握 ldconfig 的使用,逐步尝试静态库,理解两者的本质区别。
通过实践作业(如冒泡排序的调试、自定义库的调用),新手可快速掌握 Linux 下的编译流程,为后续开发打下坚实基础。记住:多写代码、多调试、多解决报错,是掌握编译器的关键!