程序翻译过程
程序翻译一般分为以下四个步骤:
预处理:展开头文件、去除注释、宏替换、条件编译等。
编译:将 C 代码转换为汇编语言。
汇编:将汇编语言转换为二进制目标文件。
链接:将用户代码和标准库链接,生成最终可执行文件。
# 预处理
gcc -E test.c -o test.i
# -E:仅执行预处理,生成的文件是test.i
# 编译为汇编
gcc -S test.c -o test.s
# -S:编译完成汇编,不继续生成目标文件
# 汇编为二进制目标文件
gcc -c test.s -o test.o
# -c:生成目标文件test.o
# 链接,生成可执行文件
gcc test.o -o test
# 将目标文件与库进行链接,生成可执行文件test
动态链接与静态链接
在代码中调用库函数时,实际只调用了函数名,函数实现是在链接阶段完成的。链接分为动态链接和静态链接两种方式。
动态链接
可执行文件较小,节省内存、磁盘和网络资源。
运行时直接调用动态链接库
.so
文件。
静态链接
在编译时将所需的库代码拷贝到可执行文件中,生成的可执行文件较大。
不依赖外部库版本变化。
查看库的链接类型
使用 file
命令查看可执行文件是否为动态链接:
file test
输出结果示例:
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, not stripped
示例中 dynamically linked
表明此程序是动态链接的。
使用 ldd
命令查看动态库依赖:
ldd test
输出示例:
linux-vdso.so.1 (0x00007a3c38b04000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007a3c38800000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007a3c38711000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007a3c38a9c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007a3c38520000)
动态库与静态库的命名规则
动态库:以
.so
为后缀,前缀为lib
,如libc.so
是 C 标准库。静态库:以
.a
为后缀,前缀为lib
,如libm.a
是数学库。
静态链接示例
使用静态库进行链接:
g++ test.cpp -o test -static
使用静态链接生成的可执行文件通常比动态链接的大得多。
Linux 项目自动化构建工具:Make 和 Makefile
在大型项目中,Makefile 用于定义编译规则,指定编译顺序。使用 make
命令可自动化编译,提升开发效率。
Makefile 原理
一个简单的 Makefile 示例:
mycode: mycode.c # mycode 依赖于 mycode.c
gcc mycode.c -o mycode
Makefile 中的每一行命令必须以 TAB 键 开头。常用的命令如 .PHONY
表示伪目标,始终执行。
.PHONY: clean # 伪目标 clean
clean:
rm -rf mycode # 清理生成的文件
Makefile 示例:手动实现进度条
Makefile
test: main.cpp test.cpp test.h
g++ test.cpp main.cpp -o test -DN=3
.PHONY: clean
clean:
rm -rf test
test.cpp
#include "test.h"
string sc = ">-=#+*%@$)";
string g = "|\\-/";
void test() {
char bar[101] = "";
memset(bar, 0, sizeof(bar));
int start = 0;
while (start <= 100) {
printf("[%-100s]|[%d%%]|[%c]\r", bar, start, g[start % 4]);
fflush(stdout);
bar[start++] = sc[N];
usleep(50000);
}
}
main.cpp
#include "test.h"
int main() {
test();
return 0;
}
test.h
#pragma once
#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;
extern void test();
makefile 构建多个可执行文件
makefile 从上往下默认生成一个可执行文件
生成多个可执行问价的方法
.PHONY:all
all:mybin myexec
mybin:mybin.c
gcc -o $@ @^
myexec:myexec.c
gcc -o $@ @^
.PHONY:clean
rm -rf myexec mybin
GDB-Linux 调试工具
GDB 是一个强大的调试工具,用于调试 C/C++ 程序。在编译时加入 -g
选项可以生成调试信息。
g++ test.cpp -o test -g
常用 GDB 命令
l
或list
:列出当前代码。r
或run
:运行程序。n
或next
:单步执行,不进入函数内部。s
或step
:单步执行,进入函数内部。b
或break
:在指定行或函数设置断点。p
或print
:打印表达式的值。c
或continue
:继续运行程序。quit
:退出 GDB。
以下是一些调试命令的示例:
gdb test # 启动 GDB
b main # 在 main 函数设置断点
r # 运行程序
n # 单步执行
p var # 打印变量 var 的值
c # 继续运行
quit # 退出 GDB
安装 GDB
如果系统没有安装 GDB,可以通过包管理器安装,例如:
sudo pacman -S gdb