附录 A:编译与调试

← 返回目录

A.1 clang++ 常用参数

clang++ 源文件.cpp -o 程序名          # 编译+链接,生成可执行
clang++ -std=c++26 源文件.cpp -o 程序名  # 指定标准版本
clang++ -O2 源文件.cpp -o 程序名        # 优化(-O0 不优化,调试用)
clang++ -Wall -Wextra 源文件.cpp -o 程序名  # 打开全部警告(必开!)
clang++ -g 源文件.cpp -o 程序名          # 生成调试信息(配合 gdb)
clang++ a.cpp b.cpp -o app               # 多文件一起编译

常用标准版本:

-std=c++17  -std=c++20  -std=c++23  -std=c++26

推荐日常命令(复制收藏):

clang++ -std=c++26 -Wall -Wextra -O2 源文件.cpp -o 程序名

A.2 警告 = 编译器在提醒你写错了

-Wall       打开常见警告
-Wextra     更多警告
-Werror     把警告当错误(CI 用)
-pedantic   检查严格标准符合性

开发时警告必开。警告不是噪音——是编译器免费送的代码审查。 (旧编译器可能误报,21 版 clang 很准,放心开。)

A.3 调试:printf 大法 与 gdb

  1. 最简单的调试 = println 打印变量:
   std::println("调试:i={} v={}", i, v);

打几行,跑一遍,看输出,删掉。80% 的 bug 靠这个解决。

  1. 正式调试器 gdb(Termux 可装 pkg install gdb):
   clang++ -g -std=c++26 bug.cpp -o bug
   gdb ./bug
   (gdb) run              # 运行
   (gdb) break 15         # 第 15 行设断点
   (gdb) print x          # 打印变量
   (gdb) next / step      # 单步
   (gdb) bt               # 崩溃时的调用栈(最重要!)
  1. 崩溃时先看什么:

A.4 常见编译错误对照(人话翻译)

"error: use of undeclared identifier 'x'"
    → 用了没声明的变量,多半拼错名或忘声明

"no matching function for call to..."
    → 函数不存在或参数类型对不上(或忘 include 头文件)

"member access into incomplete type"
    → 忘了 include 对应的头文件

"cannot bind non-const lvalue reference..."
    → 给 const& 传了临时对象,或 & 传了不能改的东西

"redefinition of..."
    → 同名函数/变量定义了两遍(头文件没加 include guard)

"undefined reference to..."
    → 链接错误:声明了但没定义(多文件时漏编译了某个 .cpp)

"no member named 'println'"
    → 忘了 #include <print>(C++23 才有,或忘加 -std=c++23/26)

"Segmentation fault"(运行时)
    → 空指针解引用 / 越界 / 悬空指针,配合 gdb 查

A.5 头文件与多文件项目

项目结构(大型):

project/
  include/   头文件 .hpp
  src/       源文件 .cpp
  build/     编译产物

编译多个文件:

clang++ -std=c++26 src/main.cpp src/utils.cpp -Iinclude -o app

头文件防重复包含:

// myheader.hpp
#pragma once        // 现代写法,一行搞定(clang 支持)
// 或传统写法:
// #ifndef MYHEADER_HPP
// #define MYHEADER_HPP
// ...
// #endif

声明放头文件、定义放 .cpp:

// math.hpp
int add(int a, int b);        // 只有声明

// math.cpp
int add(int a, int b) { return a + b; }   // 定义

A.6 CMake:正式项目的构建工具

# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(myapp CXX)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(app src/main.cpp src/math.cpp)

构建命令:

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/app

(Termux 已装 cmake + ninja,构建用 ninja 更快:

cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build)

A.7 遇到 bug 的排查顺序(清单)

  1. 编译过了吗?警告看了吗?(先消掉所有警告)
  2. 检查输入:是不是给了空容器/空字符串/负数/极大数?
  3. 打印关键变量,逐步逼近(printf 大法)
  4. 是不是悬空指针/越界?(sanitizer 一开见分晓):
   clang++ -fsanitize=address,undefined -g 源文件.cpp -o app
   这能自动检测内存错误,Termux 上可能受限于环境,能用尽量用
  1. 问自己:这段代码假设了什么?(假设经常就是 bug 所在)

A.8 Termux 专属小贴士

cppreference.com(权威文档,中英双语)