第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
我的习惯: 我一般会装最新版,因为旧版本对C11/C17的支持不太好。你可以在终端里敲 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
注意: 默认情况下,Cppcheck只检查错误级别的问题。如果你想检查性能、风格、可移植性等问题,记得加 --enable=all。不过要做好心理准备——警告可能会多到让你怀疑人生。

4.3 自定义规则

说实话,内置规则有时候不够用。比如你们团队有个约定:所有malloc之后必须检查返回值。这种规则Cppcheck默认不检查,但你可以自己写。

Cppcheck支持两种自定义规则的方式:

  1. 配置文件(.cfg):适合简单的规则
  2. 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
避坑指南: 我曾经写过一条规则,想检查所有没有加static的全局变量。结果一跑,整个项目报了2000多个警告。后来我加了白名单,只检查新代码。嗯,有时候规则太严也不是好事。

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
注意: 集成到构建系统后,建议在CI/CD流水线里也加上这一步。我见过太多人本地不跑,等提交到GitHub才被CI拦住。那时候改代码就晚了。

4.5 分析报告解读

报告出来了,怎么看?我一般按这个顺序:

  1. 先看错误(error):内存泄漏、数组越界、空指针解引用——这些必须修
  2. 再看警告(warning):未初始化变量、逻辑错误——建议修
  3. 最后看风格(style):命名不规范、缩进问题——看心情修

举个例子,假设报告里有这么一条:

[src/main.c:42]: (error) Memory leak: ptr

这说明第42行有个内存泄漏。你想想看,如果这个函数被调用1000次,内存就泄漏1000次。这种问题必须零容忍。

我的经验: 刚开始用Cppcheck的时候,别开 --enable=all。先只开错误级别,等团队适应了再慢慢放开。否则一下子几百个警告,大家直接躺平了。

知识体系图

下面这张图总结了本章的核心内容,你可以把它当作一个快速参考:

Cppcheck 实战 安装 Linux: apt-get install macOS: brew install Windows: vcpkg / 官网 基本用法 --enable=all 全开 --suppress 抑制 --xml 输出报告 自定义规则 .cfg 配置文件 Python 脚本 团队约定检查 集成构建系统 CMake: add_custom_target Makefile: make cppcheck CI/CD 流水线 报告解读 error → 必须修 warning → 建议修 style → 看心情

这张图把Cppcheck的五个核心环节串起来了。从安装到报告解读,每一步都有它的价值。我个人觉得,最容易被忽视的是自定义规则和报告解读——很多人装完就跑一下默认检查,然后就不管了。其实真正能提升代码质量的,恰恰是那些针对你项目定制的规则。

总结一下: Cppcheck不是银弹,但它是一个很好的起点。它能帮你发现那些肉眼很难看出来的问题。我建议你从今天开始,把Cppcheck加到你的日常开发流程里。哪怕每天只跑一次,也比从来不跑强。
公众号:蓝海资料掘金营,微信 deep3321