必须先生成compile_commands.json,因为clang-tidy依赖真实编译上下文(如-std、-i路径、宏定义)才能准确解析代码;缺失该文件将导致头文件找不到、模板推导失败等误报漏报。

直接用 clang-tidy 和 cppcheck 两个工具配合使用,基本覆盖 90% 以上常见缺陷。单独依赖任何一个都容易漏检——clang-tidy 强在语义理解与现代 C++ 规范,cppcheck 强在内存/数据流层面的越界与泄漏检测,二者互补性极强。
为什么必须先生成 compile_commands.json?
clang-tidy 不是语法扫描器,它需要知道每个文件实际怎么编译:用了什么 -std、哪些 -I 路径、是否定义了 DEBUG 宏。没有 compile_commands.json,它会按默认配置解析,结果大量误报或漏报(比如找不到头文件、模板推导失败)。
- CMake 项目:在构建目录运行
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..,文件会自动生成在当前目录 - 非 CMake 项目:可用
compdb从ninja或make日志提取,不建议手写 - 验证是否有效:用
jq '.[0].file' compile_commands.json看第一条记录是否指向你的真实源文件
clang-tidy 常见误用与修复参数
很多人只跑 clang-tidy main.cpp --,结果报一堆“unknown type name”或“use of undeclared identifier”。这不是规则问题,是上下文缺失。
- 正确姿势:
clang-tidy -p . src/**/*.cpp -- -std=c++17,其中-p .指向compile_commands.json所在目录 - 禁用冗余检查:加
-checks="-*,cppcoreguidelines-*,modernize-use-auto",避免全开--enable=all导致噪音过大 - 自动修复安全项:
-fix只对modernize-use-auto、readability-identifier-naming这类无副作用的规则生效;别指望它修内存泄漏 - 注意路径通配符:shell 展开由终端完成,
src/*.cpp在 zsh 中可能不匹配隐藏文件,用src/**/*.cpp更稳妥(需开启 globstar)
cppcheck 怎么避免“查出一堆系统头文件错误”?
cppcheck 默认不识别标准库头文件路径,一遇到 #include <vector></vector> 就报 missingIncludeSystem,干扰主线问题。
- 加
--suppress=missingIncludeSystem抑制该警告 - 指定标准库路径:
--std=c++17(不是-std=c++17),否则std::类型无法识别 - 启用关键检查组:
--enable=warning,performance,portability,比--enable=all更聚焦真实风险 - 退出码控制:
--error-exitcode=1让 CI 流程能根据是否发现问题自动失败,但注意它把 warning 也当 error,慎用于 PR 检查
报告整合与持续集成的关键细节
两个工具输出格式不统一,直接拼接日志很难读。真正落地时得做一层轻量封装:
-
clang-tidy导出 JSON:clang-tidy -p . -export-fixes=fixes.yaml src/*.cpp --,后续可批量应用修复 -
cppcheck输出 XML:cppcheck --xml --xml-version=2 src/ 2> cppcheck.xml,再用cppcheck-htmlreport转 HTML(需提前装pygments) - CI 中别让两者串行阻塞:用
timeout 5m cppcheck ... || true防止某个大文件卡死整个流水线 - 最易被忽略的一点:
clang-tidy的.clang-tidy配置文件必须放在-p指定路径的根目录下才生效,不是项目根目录
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











