Cppcheck

← 返回目录 > ← 返回总览

相关工具推荐

工具 说明
Clang-Tidy Clang 静态分析工具,侧重现代 C++ 规则
ClangFormat C/C++ 代码格式化工具
CodeQL 语义代码分析平台,支持多语言
Pre-commit Git pre-commit 钩子管理框架

1. 简介

Cppcheck 是一款免费开源的 C/C++ 静态代码分析工具,专注于检测编译器通常无法发现的深层缺陷。与编译器不同,Cppcheck 不检查语法错误,而是专门检测代码中的**未定义行为(Undefined Behavior)**和危险编码模式,如内存泄漏、空指针解引用、数组越界、未初始化变量等。

Cppcheck 采用自研的词法/语法解析器构建抽象语法树(AST),通过双向数据流分析(非仅前向分析)和符号执行技术进行多路径控制流联合分析,无需依赖编译环境即可直接扫描源代码。它支持 C89/C99/C11/C17/C23 以及 C++03/C++11/C++14/C++17/C++20/C++23/C++26 等主流标准,并兼容 GNU C 扩展、MSVC 扩展及各类嵌入式编译器的非标准语法。

  • 主要检查语言:C、C++
  • 主要检查能力:检测未定义行为、内存管理缺陷、安全漏洞、性能问题和代码风格问题;涵盖质量类检查(error、warning)、安全类检查(buffer overflow、null pointer)、性能检查(performance)、可移植性检查(portability)
  • 核心检查原理:自研 AST 解析器,双向数据流分析,无需编译即可分析
  • 检查规则/选项:按约 27 个类别组织(如 64-bit portability、Bounds checking、Memory leaks、Null pointer、STL usage 等),完整列表可通过 cppcheck --errorlist 获取,全量 check 列表
  • GitHub 仓库https://github.com/cppcheck-opensource/cppcheck(6,643 stars)
  • 开源协议:GPL-3.0-or-later
  • 最新稳定版本:2.21.0(2026-06-04 发布,date-based 版本号)
  • 运行环境要求:无(独立二进制,不依赖编译器)
  • 误报率:中

2. 官方文档

资源 链接 说明
官方网站 https://cppcheck.sourceforge.io/ Cppcheck 官方主页,提供下载、功能介绍和文档链接
用户手册(PDF) https://cppcheck.sourceforge.io/manual.pdf 官方完整用户手册,包含所有命令行选项、配置方式和抑制语法
所有检查列表 https://sourceforge.net/p/cppcheck/wiki/ListOfChecks/ 官方 Wiki 上的所有检查项分类说明
GitHub 仓库 https://github.com/cppcheck-opensource/cppcheck 源代码、Issue 跟踪和 Releases
Bug 跟踪系统 https://trac.cppcheck.net/ 官方 Trac 缺陷跟踪和功能请求系统
GitHub Releases https://github.com/cppcheck-opensource/cppcheck/releases 各版本发布说明和新特性

3. 社区优秀实践

3.1 Blender

Blender 是全球领先的开源 3D 创作套件,其核心渲染引擎和模拟系统使用 C/C++ 编写。Blender 在 CI 流水线中集成了多种静态分析工具来保障代码质量。

  • 仓库https://github.com/blender/blender
  • 语言:C, C++, Python
  • 实践方式:Blender 在其 CI 系统中使用 clang-formatclang-tidycppcheck 等工具链进行代码质量检查。项目在 tools/check_source/ 目录下提供了代码检查脚本,通过自动化流水线在每次提交时执行静态分析,确保代码符合项目规范。

3.2 CMake

CMake 是跨平台的开源构建系统生成器,本身使用 C++ 编写,是 C/C++ 项目的事实标准构建工具。

3.3 Godot Engine

Godot 是一款功能丰富的开源游戏引擎,支持 2D 和 3D 游戏开发。其核心引擎使用 C++ 编写。

  • 仓库https://github.com/godotengine/godot
  • 语言:C++, C
  • 生态参考项目:Godot 在 CI/CD 流水线中使用 SCons 和 CMake 构建系统,并集成静态分析工具进行代码质量管控。

4. 工具配置说明

4.1 配置文件说明

Cppcheck 支持多种配置方式:

配置文件 用途 使用场景
cppcheck.cfg 项目级配置文件(INI 格式) 定义检查级别、排除目录、头文件路径、宏定义等
.cppcheck-suppress 抑制规则文件 定义团队统一的告警抑制规则
compile_commands.json 编译数据库 自动获取宏定义和头文件路径,由 CMake 生成

方式一:cppcheck.cfg 配置文件

在项目根目录创建 cppcheck.cfg 文件,Cppcheck 会自动读取该文件中的配置:

# cppcheck.cfg - Cppcheck 项目配置文件
# 启用的检查级别
enable=warning,performance,portability,style

# 排除的目录
exclude=third_party/
exclude=build/
exclude=test/

# C++ 标准
std=c++17

# 头文件路径
include=include/
include=third_party/include/

# 宏定义
define=DEBUG=1
define=MYPROJECT_EXPORTS

# 抑制规则
suppress=missingInclude
suppress=unusedFunction:test/*

参考文档https://cppcheck.sourceforge.io/manual.pdf("Project configuration" 章节)

方式二:使用编译数据库

# 生成编译数据库
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .

# 使用编译数据库进行分析(自动获取宏定义和头文件路径)
cppcheck --project=compile_commands.json --enable=all

参考文档https://cppcheck.sourceforge.io/manual.pdf("Compilation database" 章节)

4.2 配置详解

配置项说明(cppcheck.cfg 配置项 + 常用命令行参数):

配置项/参数 类型 说明
enable string 启用的检查级别(warningperformanceportabilitystyleinformationall
exclude string 排除的目录
std string C/C++ 标准(如 c++17
include string 头文件路径
define string 宏定义
suppress string 抑制规则
--inconclusive flag 显示不确定的分析结果,提高缺陷检出率
--inline-suppr flag 允许代码中的内联抑制注释生效
--force flag 强制分析所有代码路径(包括 #ifdef 分支)
-j int 并行检查线程数
--check-level string 检查级别(reducednormalexhaustive
--error-exitcode int 发现问题时返回的退出码
--suppressions-list string 抑制规则文件路径
--output-format string 报告输出格式(如 sarif
--output-file string 报告输出文件路径
-I string 头文件搜索路径
-i string 排除的文件或目录
--cppcheck-build-dir string 增量分析缓存目录

推荐配置一:日常开发(平衡精度与速度)

适用于日常开发,重点关注错误和警告,兼顾性能和可移植性,避免过多的风格告警干扰。

cppcheck \
  --enable=warning,performance,portability,style \
  --inconclusive \
  --std=c++17 \
  --inline-suppr \
  --force \
  -j 4 \
  --suppress=missingInclude \
  --suppress=missingIncludeSystem \
  -I include/ \
  src/

参数说明

参数 说明
--enable=warning,performance,portability,style 启用警告、性能、可移植性和风格检查(不含 information)
--inconclusive 显示不确定的分析结果,提高缺陷检出率
--std=c++17 指定 C++17 标准
--inline-suppr 允许代码中的内联抑制注释生效
--force 强制分析所有代码路径(包括 #ifdef 分支)
-j 4 使用 4 个线程并行检查
--suppress=missingInclude 抑制缺少头文件的告警(通常不影响分析)
--suppress=missingIncludeSystem 抑制缺少系统头文件的告警

推荐配置二:CI/CD 流水线(严格模式)

适用于 CI/CD 环境,启用所有检查,配合错误退出码实现质量门禁。

cppcheck \
  --enable=all \
  --inconclusive \
  --std=c++17 \
  --inline-suppr \
  --force \
  --check-level=exhaustive \
  -j 4 \
  --error-exitcode=1 \
  --suppressions-list=.cppcheck-suppress \
  --output-format=sarif \
  --output-file=cppcheck-report.sarif \
  -I include/ \
  -i build/ \
  -i third_party/ \
  src/

参数说明

参数 说明
--enable=all 启用所有检查类型(包括 information)
--check-level=exhaustive 使用最高检查级别(分析更彻底,耗时更长)
--error-exitcode=1 发现问题时返回非零退出码,使 CI 构建失败
--suppressions-list=.cppcheck-suppress 加载团队统一的抑制规则文件
--output-format=sarif 输出 SARIF 格式报告,便于 CI 工具解析
-i build/ -i third_party/ 排除构建目录和第三方库

推荐配置三:快速检查模式(大型项目)

适用于大型项目中的日常快速检查,牺牲部分检出率换取速度。

cppcheck \
  --check-level=reduced \
  --enable=warning \
  --std=c++17 \
  --inline-suppr \
  -j 8 \
  --error-exitcode=1 \
  --cppcheck-build-dir=.cppcheck-cache \
  -I include/ \
  src/

参数说明

参数 说明
--check-level=reduced 使用 reduced 级别,分析更快但部分结果会减少(2.17.0 新增)
--cppcheck-build-dir=.cppcheck-cache 启用增量分析缓存,后续运行仅检查变更文件

4.3 .cppcheck-suppress 抑制文件

# .cppcheck-suppress - 团队统一抑制规则
# ========================================
# 缺少头文件(通常不影响分析质量)
missingInclude
missingIncludeSystem

# 第三方库告警(不修改第三方代码)
*:third_party/*

# 测试代码中的特定告警
unusedFunction:test/*
uninitvar:test/*

# 已知误报(需附注释说明原因)
# TODO: 升级 Cppcheck 后移除此抑制
uninitvar:src/legacy/module.c

5. 主流集成方式

5.1 CMake 集成(生态主流)

CMake 是 C/C++ 项目的主流构建工具,也是 Cppcheck 最常见的集成方式。

方式一:通过 CMAKE_CXX_CPPCHECK 属性

CMakeLists.txt 中设置,使 Cppcheck 在每次编译时自动运行:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找 Cppcheck 并设置
find_program(CPPCHECK_EXE NAMES "cppcheck")
if(CPPCHECK_EXE)
    set(CMAKE_CXX_CPPCHECK
        ${CPPCHECK_EXE}
        --enable=warning,performance,portability
        --inconclusive
        --suppress=missingInclude
        --inline-suppr
        --std=c++17
    )
    message(STATUS "Cppcheck enabled: ${CPPCHECK_EXE}")
endif()

官方文档https://cmake.org/cmake/help/latest/prop_tgt/LANG_CPPCHECK.html

方式二:通过自定义 target

# CMakeLists.txt - 定义独立的 cppcheck target
find_program(CPPCHECK_EXE NAMES "cppcheck")
if(CPPCHECK_EXE)
    add_custom_target(cppcheck
        COMMAND ${CPPCHECK_EXE}
            --enable=all
            --inconclusive
            --inline-suppr
            --suppress=missingInclude
            --std=c++17
            -I ${PROJECT_SOURCE_DIR}/include
            ${PROJECT_SOURCE_DIR}/src
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
        COMMENT "Running Cppcheck static analysis"
        VERBATIM
    )
endif()

方式三:使用编译数据库

# 生成编译数据库(自动获取宏定义和头文件路径)
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .

# 使用编译数据库进行分析
cppcheck --project=compile_commands.json --enable=all

5.2 pre-commit 集成

使用 pocc/pre-commit-hooks 仓库提供的预置 hook,可在 Git 提交前自动运行 Cppcheck 检查暂存文件。

依赖说明:此 hook 依赖本地安装的 cppcheck(需在 PATH 中可用)。hook 使用 language: python,但实际调用的是系统中的 cppcheck 二进制。默认参数为 -q --error-exitcode=1 --enable=all --suppress=unmatchedSuppression --suppress=missingIncludeSystem --suppress=unusedFunction

# .pre-commit-config.yaml
fail_fast: false
repos:
  - repo: https://github.com/pocc/pre-commit-hooks
    rev: v1.3.5
    hooks:
      - id: cppcheck
        args: [--enable=warning, performance, portability, style]

安装 pre-commit hooks:

pip install pre-commit
pre-commit install

限制变更文件:pre-commit 框架默认仅将暂存区中的变更文件传给 hook,因此无需额外配置即可实现文件级增量检查。

5.3 IDE 集成

VS Code

安装 Cppcheck Plug-in 扩展(发布者:NathanJ,扩展 ID:NathanJ.cppcheck-plugin),支持右键菜单检查文件或文件夹,结果输出到 "Cppcheck: Errors" 和 "Cppcheck: Warnings" 通道。

前置条件:系统 PATH 中必须可用 cppcheck 二进制。

CLion

CLion 内置 Cppcheck 插件支持(JetBrains 官方插件),配置方式:

  1. 打开 Settings/Preferences -> Build, Execution, Deployment -> Static Analysis Tools -> Cppcheck
  2. 设置 Cppcheck 可执行文件路径
  3. 配置检查参数和过滤选项

Vim/Neovim

使用 ALE 插件集成 Cppcheck:

" .vimrc 或 init.vim
let g:ale_linters = {
\   'cpp': ['cppcheck'],
\   'c': ['cppcheck'],
\}
let g:ale_cpp_cppcheck_options = '--enable=warning,performance,portability,style --inconclusive --inline-suppr'

Cppcheck 也被收录为 Vim 内置 compiler,可通过 :compiler cppcheck 激活:https://vimhelp.org/quickfix.txt.html#compiler-cppcheck

5.4 命令行使用方式

基本用法

# 检查单个文件
cppcheck file.cpp

# 检查整个目录(递归)
cppcheck src/

# 检查多个文件
cppcheck file1.c file2.cpp

常用参数组合

# 推荐的日常检查命令
cppcheck \
  --enable=warning,performance,portability,style \
  --inconclusive \
  --std=c++17 \
  --inline-suppr \
  --force \
  -j 4 \
  --suppressions-list=.cppcheck-suppress \
  -I include/ \
  src/

参数说明

参数 说明
--enable=<checks> 启用特定类型的检查(见下方详细说明)
--inconclusive 显示不确定的分析结果(启发式推理)
--std=<standard> 指定 C/C++ 标准(如 c++17、c11、c23)
--inline-suppr 允许代码中的内联抑制注释生效
--force 强制分析所有代码路径(包括 #ifdef 分支)
-j <N> 使用 N 个线程并行检查
-I <dir> 添加头文件搜索路径
-i <pattern> 排除匹配指定模式的文件/目录不检查
--file-filter=<pattern> 仅检查匹配指定模式的文件
--suppress=<pattern> 抑制指定类型的警告
--suppressions-list=<file> 从文件加载抑制规则列表
--output-file=<file> 将结果输出到文件
--xml / --output-format=sarif 以 XML 或 SARIF 格式输出结果(用于 CI 集成)
--project=<file> 使用项目文件(compile_commands.json / .sln / .vcxproj)
--cppcheck-build-dir=<dir> 启用增量分析(使用构建目录缓存分析结果)
--platform=<platform> 指定目标平台(win32A、win64、unix32、unix64)
--error-exitcode=<N> 发现问题时返回指定的退出码(用于 CI)
--check-level=<level> 检查级别:normal(默认)、exhaustive(更彻底)、reduced(更快)
--template=<format> 自定义输出格式(如 gcc、vs)
--exitcode-suppress=<id> 指定不导致非零退出码的错误 ID(2.21.0 新增)

--enable 可选值

说明
error 仅检查错误(默认)
warning 启用警告检查
style 启用风格检查(包括 warning、performance、portability)
performance 启用性能检查
portability 启用可移植性检查
information 启用信息提示
unusedFunction 检查未使用的函数
missingInclude 检查缺少的头文件
all 启用所有检查

增量检查 -- Cppcheck 提供多种增量检查方式:

使用 --cppcheck-build-dir 实现增量分析(推荐)

# 首次分析(建立缓存)
cppcheck --cppcheck-build-dir=.cppcheck-cache --enable=all src/

# 后续分析(仅检查变更文件,速度大幅提升)
cppcheck --cppcheck-build-dir=.cppcheck-cache --enable=all src/

参考文档https://cppcheck.sourceforge.io/manual.pdf("Cppcheck build folder" 章节)

使用 --file-filter 仅检查特定文件

# 仅检查 src 目录下的 .c 文件
cppcheck --project=compile_commands.json --file-filter=src/*.c

# 仅检查 src/test 目录下的文件
cppcheck src/ --file-filter=src/test*

参考文档https://cppcheck.sourceforge.io/manual.pdf("Check files matching a given file filter" 章节)

基于 Git 的命令行增量方案

# 仅检查 Git 暂存区中变更的 C/C++ 文件
cppcheck --enable=warning,performance \
         --inline-suppr \
         --error-exitcode=1 \
         $(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.(c|cpp|h|hpp)$')

# 仅检查相对于 main 分支变更的文件
cppcheck --enable=all \
         $(git diff --name-only main...HEAD -- '*.cpp' '*.h' '*.c')

CI 脚本调用

GitHub Actions(手动方式)

直接安装运行 Cppcheck:

# .github/workflows/cppcheck.yml
name: Cppcheck Static Analysis

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  cppcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Cppcheck
        run: sudo apt-get update && sudo apt-get install -y cppcheck

      - name: Run Cppcheck
        run: |
          cppcheck --enable=warning,performance,portability,style \
                   --inconclusive \
                   --std=c++17 \
                   --inline-suppr \
                   --error-exitcode=1 \
                   --suppress=missingInclude \
                   -I include \
                   src/

GitLab CI

# .gitlab-ci.yml
stages:
  - static_analysis

cppcheck:
  stage: static_analysis
  image: ubuntu:22.04
  before_script:
    - apt-get update && apt-get install -y cppcheck
  script:
    - cppcheck --enable=all --inconclusive --inline-suppr
      --suppress=missingInclude
      --std=c++17
      --xml
      --output-file=cppcheck-report.xml
      src/
  artifacts:
    paths:
      - cppcheck-report.xml
    when: always
    expire_in: 1 week
  rules:
    - if: $CI_MERGE_REQUEST_ID
      when: always
    - if: $CI_COMMIT_BRANCH == "main"
      when: always

增量检查 -- GitHub Actions 中按 PR 变更文件触发增量检查:

# .github/workflows/cppcheck.yml
name: Cppcheck (Incremental)

on: [pull_request]

jobs:
  cppcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Cppcheck
        run: sudo apt-get update && sudo apt-get install -y cppcheck

      - name: Get Changed Files
        id: changed-files
        uses: tj-actions/changed-files@v44
        with:
          files: |
            src/**/*.cpp
            src/**/*.h
            src/**/*.c
            src/**/*.hpp

      - name: Run Cppcheck on Changed Files
        if: steps.changed-files.outputs.any_changed == 'true'
        run: |
          cppcheck --enable=warning,performance,portability,style \
                   --inline-suppr \
                   --error-exitcode=1 \
                   --suppress=missingInclude \
                   ${{ steps.changed-files.outputs.all_changed_files }}

5.5 GitHub Action 插件

使用 myint/cppcheck-action 在 GitHub Actions 中运行 Cppcheck:

# .github/workflows/cppcheck.yml
name: Cppcheck

on: [push, pull_request]

jobs:
  cppcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Cppcheck
        uses: myint/cppcheck-action@v1
        with:
          source: "./src"
          args: "--enable=all --suppress=missingIncludeSystem --inline-suppr --inconclusive"

参考https://github.com/myint/cppcheck-action

6. 告警抑制(屏蔽)方法

Cppcheck 提供了多种灵活的告警抑制方式,可根据场景选择最适合的方案。

参考文档https://cppcheck.sourceforge.io/manual.pdf("Suppressing certain checks" 章节)

6.1 通过代码注释屏蔽(内联抑制)

在源代码中添加特殊注释,精准抑制特定行的特定告警。需要配合 --inline-suppr 参数才能生效。

参考文档https://cppcheck.sourceforge.io/manual.pdf("Inline suppression" 章节)

单行抑制

// cppcheck-suppress nullPointer
int* ptr = get_ptr();
*ptr = 42;

带符号名的精确抑制

// cppcheck-suppress unreadVariable symbolName=buffer
char buffer[256];

抑制下一行

int x; // cppcheck-suppress uninitvar

C 风格块注释抑制

/* cppcheck-suppress memleak */
void process() {
    void* p = malloc(100);
    // ...
}

6.2 通过命令行参数屏蔽

通过 --suppress 参数在命令行中直接指定要抑制的告警。

参考文档https://cppcheck.sourceforge.io/manual.pdf("Command line suppression" 章节)

# 抑制全局特定规则
cppcheck --suppress=missingInclude src/

# 抑制特定文件中的特定规则
cppcheck --suppress=memleak:src/file1.cpp src/

# 抑制特定文件中所有规则(使用通配符)
cppcheck --suppress=*:third_party/* src/

# 同时抑制多个规则
cppcheck --suppress=missingInclude --suppress=unusedFunction src/

6.3 通过抑制文件屏蔽(suppressions-list)

将抑制规则保存在文本文件中,便于团队统一管理。

参考文档https://cppcheck.sourceforge.io/manual.pdf("Suppression file" 章节)

文本格式 .cppcheck-suppress

# 格式:errorId 或 errorId:fileName
# 抑制全局 missingInclude 告警
missingInclude

# 抑制特定文件中的 memleak 告警
memleak:src/legacy/code.cpp

# 使用通配符抑制目录
uninitvar:test/*

# 抑制特定文件中的所有告警
*:third_party/lib/*

使用方式

cppcheck --suppressions-list=.cppcheck-suppress --enable=all src/

6.4 通过 cppcheck.cfg 配置文件屏蔽

在项目配置文件中设置全局抑制规则:

# cppcheck.cfg
suppress=missingInclude
suppress=unusedFunction:test/*
suppress=memleak:src/legacy/*

6.5 通过 CMake 集成屏蔽

在 CMake 中通过 CMAKE_CXX_CPPCHECK 设置全局抑制参数:

set(CMAKE_CXX_CPPCHECK
    ${CPPCHECK_EXE}
    --enable=warning,performance,portability
    --suppress=missingInclude
    --suppress=unusedFunction:test/*
    --inline-suppr
)

6.6 抑制方式对比

方式 精度 适用场景 持久性
内联注释 // cppcheck-suppress 最高(精确到行和符号) 已知误报、临时屏蔽 随代码提交
命令行 --suppress 中等(文件/规则级别) 一次性分析、脚本 不持久
抑制文件 --suppressions-list 高(支持通配符) 团队统一管理 持久文件
cppcheck.cfg 中等 项目级全局配置 持久文件
CMake 集成参数 中等 构建系统集成 持久文件

附录:快速参考

安装方式

平台 命令
Ubuntu/Debian sudo apt-get install cppcheck
Fedora/RHEL sudo dnf install cppcheck
Arch Linux sudo pacman -S cppcheck
macOS (Homebrew) brew install cppcheck
Windows (Chocolatey) choco install cppcheck
Windows (Scoop) scoop install cppcheck
从源码编译 git clone https://github.com/cppcheck-opensource/cppcheck && cd cppcheck && cmake -S . -B build && cmake --build build

常见错误 ID 速查

错误 ID 严重性 说明
nullPointer error 空指针解引用
arrayIndexOutOfBounds error 数组越界访问
memleak error 内存泄漏
uninitvar warning 使用未初始化的变量
unusedVariable style 未使用的变量
unusedFunction style 未使用的函数
passedByValue performance 大对象值传递(建议使用 const 引用)
bufferAccessOutOfBounds error 缓冲区越界访问
resourceLeak error 资源泄漏(文件句柄等)
doubleFree error 双重释放
deallocuse error 释放后使用(use-after-free)
shiftTooManyBits error 移位操作位数过大
integerOverflow error 整数溢出
selfAssignment warning 变量自我赋值

← 返回目录 > ← 返回总览