编译不过 / 跑太慢 / 调不了 / 内存出错 / 想发布——按场景反查该敲哪几条命令
工程里你不会"背命令",而是遇到一个场景,反查该敲什么。 点下面 5 个常见场景,看每个场景推荐的命令组合和理由。
按类别筛选,或搜关键词(如 -O2、backtrace、strip)。
每条命令都有作用说明,多数附本机实测输出,命令块可整行复制。
同一条命令,换个平台可能就跑不了或产物名不同。下表都是本机实测差异,照抄前先看你用哪个平台。
| 场景 | Linux | Windows / MinGW |
|---|---|---|
| 可执行产物名 | ./hello | hello.exe(运行时 .\hello.exe) |
| make 命令名 | make | 本机 make 未装,用 mingw32-make |
| 删除文件 | rm app | del app.exe(Makefile 的 clean 里) |
| 内存检查 Sanitizer | -fsanitize=address 可用 | 本机不支持:报 cannot find -lasan(缺运行时库) |
| 动态库后缀 | .so | .dll |
| 路径分隔符 | / | \(但 g++/git 里一般也用 /) |
./hello 会报"找不到文件"——因为产物是 hello.exe,
要写 .\hello.exe。这个和 26.1「编译四步」直接相关。-O2:变量被优化掉,GDB 里 print a 报
No symbol "a" in current context。调试一律用 -O0 -g。print x 得 32758)。要先 next 走过赋值语句再看。app: 但编译成 -o app.exe,
make 永远找不到目标产物 → 每次都重编(本机实测复现)。目标名必须等于真实产物名。missing separator(见 92.2 的 E12)。
很多编辑器的"自动缩进"会偷偷把 TAB 转成空格。-fsanitize=address 直接链接失败。
Windows 想做内存检查,得用 WSL/Linux,或换 clang,或用 -Wall -Wextra 先抓一部分。print x 报 No symbol "x" in current context,最可能是?-O2 会把用不到的变量优化掉,GDB 就找不到符号。调试要用 g++ -O0 -g——-O0 关优化、-g 生成调试符号。strip app.exe 去掉符号表。本机实测:127991 bytes → 17408 bytes,瘦身约 86%。注意 strip 后就不能再用 GDB 调试了(符号没了),所以调试版和发布版要分开编。make 提示"不是内部或外部命令",应该?mingw32-make,不叫 make。本机实测:make 未安装,mingw32-make(GNU Make 3.82)可用。Q4. 链接报 undefined reference 时,92.2 教你用 nm -C app.o 查符号。
-C 是干嘛的?nm 输出里符号前的 T 和 U 分别代表什么?
-C = demangle(还原被 C++ 改编过的符号名,把 _Z3addii 显示成 add(int,int))。T = 该符号在本文件的代码段里已定义(Text,大写=全局);U = 未定义(Undefined),
即"本文件用到了它,但定义在别处,要靠链接补上"。本机实测:nm -C mk.o 输出 T main、U __main。
Q5. 你的 Makefile 每次 make 都重新编译,明明代码没改。列出至少两个可能原因。
app: 却编译成 -o app.exe,make 找不到叫 app 的产物,永远判为过期。-Encoding utf8)存文件会加 BOM,
make 把 BOM 当成目标名的一部分(-d 调试可见 Considering target file 'app.exe'),于是永远认为文件不存在。Q6. 你在 Windows(MinGW) 上想抓一个数组越界的 bug,照 Linux 教程敲
g++ -fsanitize=address -g app.cpp,却报 ld.exe: cannot find -lasan。
为什么会这样?给出至少两种可行的替代方案。
libasan(本机实测:只有个头文件 asan.h,没有链接库),
所以 -fsanitize=address 能编译却链接失败。这不是你命令写错,是平台缺库。mingw-w64-x86_64-libasan 包,或改用 clang(clang 的 ASan 在 Windows 支持更好);-Wall -Wextra 让编译器静态抓一部分(本机实测能抓到 'a' is used uninitialized 这类,
但抓不到运行时的越界写入);std::vector::at()(越界会抛 out_of_range)替代 [] 定位。
命令 [选项] [参数]、-o 指定输出、--help 查帮助、
退出码 0 表示成功。
g++ -E ... | grep 宏名 这种把几个工具的输入输出串起来的写法才成为可能——
这就是管道(pipe),34 章「信号与 IPC」会讲它的原理。