第1章:静态分析工具实战:Cppcheck
各位同学好。今天我们来聊聊Cppcheck这个工具。说实话,静态分析工具我用了十几年,Cppcheck是我个人最常用的一个。为什么?因为它轻量、实用,而且不会像某些商业工具那样动不动就报几百个假阳性。
我记得刚带团队那会儿,有个同事提交的代码里藏了个很隐蔽的数组越界。Code Review过了三遍都没发现,最后还是Cppcheck一把揪出来的。从那以后,我就把Cppcheck写进了团队的代码规范里。
4.1 安装Cppcheck
安装这事儿其实很简单。不同平台有不同玩法,我分别说说。
Linux(Ubuntu/Debian)
sudo apt-get install cppcheck
macOS
brew install cppcheck
Windows
去官网下载安装包,或者用vcpkg:
vcpkg install cppcheck
cppcheck --version 确认版本号。
4.2 基本用法
安装完了,咱们先跑个最简单的例子。假设你有这么个文件 test.c:
#include <stdio.h>
void foo() {
int arr[10];
arr[10] = 42; // 越界了
}
int main() {
foo();
return 0;
}
在终端里执行:
cppcheck test.c
你会看到类似这样的输出:
Checking test.c ...
[test.c:5]: (error) Array 'arr[10]' accessed at index 10, which is out of bounds.
看到了吧?它直接告诉你第5行有问题。这就是Cppcheck的厉害之处——不需要你编译,不需要你运行,光看代码就能发现问题。
常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
--enable=all |
启用所有检查 | cppcheck --enable=all test.c |
--suppress=* |
抑制某些警告 | cppcheck --suppress=unusedFunction test.c |
--xml |
输出XML格式报告 | cppcheck --xml test.c 2> report.xml |
--std=c11 |
指定C标准 | cppcheck --std=c11 test.c |
--enable=all。不过要做好心理准备——警告可能会多到让你怀疑人生。
4.3 自定义规则
说实话,内置规则有时候不够用。比如你们团队有个约定:所有malloc之后必须检查返回值。这种规则Cppcheck默认不检查,但你可以自己写。
Cppcheck支持两种自定义规则的方式:
- 配置文件(.cfg):适合简单的规则
- Python脚本:适合复杂的规则
举个配置文件的例子
创建一个 myrules.cfg:
<?xml version="1.0"?>
<def>
<rule>
<pattern>malloc\(.*\)</pattern>
<message>检查malloc返回值了吗?</message>
<severity>warning</severity>
</rule>
</def>
然后这样用:
cppcheck --suppressions-list=myrules.cfg test.c
4.4 集成到构建系统
手动跑Cppcheck当然可以,但更靠谱的做法是把它集成到构建系统里。这样每次编译的时候自动检查,省心省力。
集成到CMake
在 CMakeLists.txt 里加这么一段:
find_program(CPPCHECK cppcheck)
if(CPPCHECK)
add_custom_target(
cppcheck
COMMAND ${CPPCHECK}
--enable=all
--suppress=missingInclude
--std=c11
--xml
${CMAKE_SOURCE_DIR}/src
2> ${CMAKE_BINARY_DIR}/cppcheck_report.xml
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Running Cppcheck static analysis..."
)
endif()
然后执行:
cmake --build . --target cppcheck
集成到Makefile
在 Makefile 里加:
cppcheck:
cppcheck --enable=all --suppress=missingInclude --std=c11 src/ 2> cppcheck_report.txt
然后:
make cppcheck
4.5 分析报告解读
报告出来了,怎么看?我一般按这个顺序:
- 先看错误(error):内存泄漏、数组越界、空指针解引用——这些必须修
- 再看警告(warning):未初始化变量、逻辑错误——建议修
- 最后看风格(style):命名不规范、缩进问题——看心情修
举个例子,假设报告里有这么一条:
[src/main.c:42]: (error) Memory leak: ptr
这说明第42行有个内存泄漏。你想想看,如果这个函数被调用1000次,内存就泄漏1000次。这种问题必须零容忍。
--enable=all。先只开错误级别,等团队适应了再慢慢放开。否则一下子几百个警告,大家直接躺平了。
知识体系图
下面这张图总结了本章的核心内容,你可以把它当作一个快速参考:
这张图把Cppcheck的五个核心环节串起来了。从安装到报告解读,每一步都有它的价值。我个人觉得,最容易被忽视的是自定义规则和报告解读——很多人装完就跑一下默认检查,然后就不管了。其实真正能提升代码质量的,恰恰是那些针对你项目定制的规则。