CppCheck代码静态检测工具

CppCheck是一款静态代码检查工具,专注于检查编译器无法检测的C/C++代码错误。本文介绍了CppCheck的安装、使用方法,包括检查单个文件、整个文件夹,设置检查级别,以及与其他工具如cmake、git的集成,帮助提高代码质量和可维护性。

一、简述

Cppcheck是一种C/C++代码缺陷静态检查工具。不同于 C/C++ 编译器及很多其它分析工具,它不检查代码中的语法错误。Cppcheck只检查编译器检查不出来的bug类型,其目的是检查代码中真正的错误。

支持的代码和平台:

  • 可以检查非标准代码,包括不同的编译器扩展、内联汇编代码等。
  • Cppcheck应该被处理最新C++标准的任何C++编译器所编译。
  • Cppcheck应该在任何有足够CPU和内存的平台上工作。

要知道Cppcheck有限制,Cppcheck很少在报告错误方面出错,但有很多bug,它不能检测。

通过仔细测试软件,你会发现软件中有更多的bug,而不是使用Cppcheck。但Cppcheck仍可以检测到在测试和评估软件时错过的一些bug。

二、安装

可以直接在GitHub上克隆代码,然后切换到对应版本后进行编译安装:

$ git clone git@github.com:danmar/cppcheck.git
$ cd cppcheck
$ git checkout 1.87
$ cd ..
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/cppcheck-1.87 ../cppcheck/
$ make SRCDIR=build CFGDIR=cfg HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function"
$ make install

然后修改PATH环境变量,添加/opt/cppcheck-1.87/bin到PATH中。

二、使用

2.1 第一个测试程序

下面是一个简单的代码:

int main()
{
	char a[0];
	a[10] = 0;
	return 0;
}

将代码保存进file1.c中,然后执行:

cppcheck file1.c

将得到如下输出:

Checking file1.c...
[file1.c:4]: (error) Array 'a[10]' index 10 out of bounds

2.2 检查文件夹中所有文件

通常一个项目会有许多源文件,如果需要同时检查,Cppcheck可以检查文件夹中的所有文件:

cppcheck path

如果path是一个文件夹,cppcheck将递归检查这个文件夹中的所有源文件。
···
Checking path/file1.cpp…
1/2 files checked 50% done
Checking path/file2.cpp…
2/2 files checked 100% done
···

2.3 检查部分或过滤部分文件

排除一个文件或文件夹有两个选项,第一个选项是只提供你想检查的路径和文件:

cppcheck src/a src/b

所有位于 src/a 和 src/b 下的文件都会被检查。

如果使用-i选项,将会忽略指定的文件/文件夹,使用下面命令src/c将不会被检查:

cppcheck -isrc/c src

三、严重性

cppcheck的严重性等级可能为:

  • 错误(error): 当发现bug时使用
  • 警告(warning): 关于防御性编程,以防止bug的建议
  • 风格警告(style): 风格有关问题的代码清理(未使用的函数、冗余代码、常量性等等)
  • 可移植性警告(portability): 可移植性警告。64 位的可移植性,代码可能在不同的编译器中运行结果不同。
  • 性能警告(performance): 建议使代码更快。这些建议只是基于常识,即使修复这些消息,也不确定会得到任何可测量的性能提升。
  • 信息消息(information): 配置问题,建议在配置期间仅启用这些。

四、其他常用用法

4.1 启用其他检查

默认情况下,cppcheck只检测错误信息,可以通过–enable选项启用更多的检查:

# enable warning messages
cppcheck --enable=warning file.c

# enable performance messages
cppcheck --enable=performance file.c

# enable information messages
cppcheck --enable=information file.c

# For historical reasons, --enable=style enables warning, performance,
# portability and style messages. These are all reported as "style" when
# using the old xml format.
cppcheck --enable=style file.c

# enable warning and performance messages
cppcheck --enable=warning,performance file.c

# enable unusedFunction checking. This is not enabled by --enable=style
# because it doesn't work well on libraries.
cppcheck --enable=unusedFunction file.c

# enable all messages
cppcheck --enable=all

注意:–enable=unusedFunction和–enable=all应该只在进行项目工程检查是才启用。因为unusedFunction会将未使用的函数报告为警告。

4.2 保存结果到文件

很多时候,会希望将结果保存在一个文件中,可以使用 shell 的管道重定向错误输出到一个文件:

cppcheck file1.c 2> err.txt

4.3 多线程检查

选项-j用于指定需要使用的线程数,例如,使用6个线程检查文件夹中的文件:
cppcheck -j 6 path

注意:这将禁用unusedFunction检查。

4.3 设置目标平台

应该使用一个与你的目标匹配的平台配置。默认情况下,如果代码在本地编译和执行,Cppcheck会使用本地平台配置。

Cppcheck具有用于Unix和Windows目标的内置配置,可以轻松地使用这些 --platform 命令行标志。

    --platform=<type>, --platform=<file>
                         Specifies platform specific types and sizes. The
                         available builtin platforms are:
                          * unix32
                                 32 bit unix variant
                          * unix64
                                 64 bit unix variant
                          * win32A
                                 32 bit Windows ASCII character encoding
                          * win32W
                                 32 bit Windows UNICODE character encoding
                          * win64
                                 64 bit Windows
                          * avr8
                                 8 bit AVR microcontrollers
                          * native
                                 Type sizes of host system are assumed, but no
                                 further assumptions.
                          * unspecified
                                 Unknown type sizes

还可以在 XML 文件中创建自己的自定义平台配置。这里有一个例子:

<?xml version="1"?>
<platform>
  <char_bit>8</char_bit>
  <default-sign>signed</default-sign>
  <sizeof>
    <short>2</short>
    <int>4</int>
    <long>4</long>
    <long-long>8</long-long>
    <float>4</float>
    <double>8</double>
    <long-double>12</long-double>
    <pointer>4</pointer>
    <size_t>4</size_t>
    <wchar_t>2</wchar_t>
  </sizeof>
</platform>

4.4 与cmake项目配合使用

当使用CMake时,可以使用–project来分析项目。

它会给你快速和简单的结果,不需要做太多的配置。但很难说这是否将会给你最好的结果,建议试一试它,并尝试不使用–project分析源代码,看哪个选项更适合。

Cppcheck可以理解编译数据库,可以用CMake生成这些。例如在编译代码时:

$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

则会在编译目录创建compile_commands.json文件,然后使用cppcheck检查项目:

$ cppcheck --project=compile_commands.json

4.5 宏定义

假如这里有个文件,有两个配置(定义和没有定义A):

#ifdef A
    x = y;
#else
    x = z;
#endif

默认情况下,Cppcheck将检查所有预处理器配置(除了那些具有#error的配置),所以上述代码将被分析在当A定义和不定义的情况下。

可以使用-D更改:当使用-D时,cppcheck将默认只检查给定的配置,不会检查其它,这就是编译器的工作原理。但是可以使用–force或–max-configs来覆盖配置数量。

# check all configurations
cppcheck file.c
# only check the configuration A
cppcheck -DA file.c
# check all configurations when macro A is defined
cppcheck -DA --force file.c

另一个有用的标志可能是 -U,它未定义符号。用法示例:

cppcheck -UX file.c

这意味着X没有定义,Cppcheck不会检查当定义X时会发生什么。

4.6 XML格式输出

cppcheck可以按照XML格式输出检查结果,通过使用–xml添加这种支持。

$ cppcheck --xml file1.cpp
<?xml version="1.0" encoding="UTF-8"?>
<results version="2">
	<cppcheck version="1.66">
	<errors>
		<error id="someError" severity="error" msg="short error text"
				verbose="long error text" inconclusive="true" cwe="312">
			<location file0="file.c" file="file.h" line="1"/>
		</error>
	</errors>
</results>

输出中每个错误都在元素中,其属性包括:

  • id: 错误的id,这些都是有效的符号名称。
  • severity: error、warning、style、performance、portability、information中的任何一个。
  • msg: 短格式的错误消息。
  • verbose: 长格式的错误消息。
  • inconclusive: 此属性仅在消息不确定时使用。
  • cwe: 消息的CWE ID,此属性仅在消息的CWE ID已知时使用。

元素列出所有错误相关位置,首先列出主要位置,包括如下属性:

  • file: 文件名,相对路径和绝对路径都是可能的。
  • file0: 源文件的名称(可选)。
  • line: 一个数字。
  • msg: 此属性尚不存在,但将来可以为每个位置添加一条短消息。

4.7 让git提交前支持CPPCheck

进入Cppcheck官网,找到Clients and plugins章节,里面有不同工具的插件支持,包括Clion、gedit、Jenkins、SVN和Git等。点击Git对应的插件,可以找到如下代码:

#!/bin/sh

# Usage: add this file to your project's .git/hooks directory. Rename it to
# just 'pre-commit'.
# Now, when you change some files in repository and try to commit these
# changes, git will run this script right before commit. Cppcheck will scan
# changed/new files in repository. If it finds some issues, script returns with
# exit code 1, rejecting commit. Otherwise, script returns 0, and you can
# actually commit your changes.
#
# Example:
# $ cat hello.c
# int main() {
#    int *s = malloc(10);
# }
# $ git add hello.c
# $ git commit
# Checking hello.c...
# [hello.c:3]: (error) Memory leak: s
# [hello.c:2]: (error) The allocated size 10 is not a multiple of the underlying type's size.
#
# $ vim hello.c
# $ cat hello.c
# int main() {
# }
# $ git add hello.c
# $ git commit
# Checking hello.c...
# $

if git rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# We should pass only added or modified C/C++ source files to cppcheck.
changed_files=$(git diff-index --cached $against | \
	grep -E '[MA]	.*\.(c|cpp|cc|cxx)$' | cut -f 2)

if [ -n "$changed_files" ]; then
	cppcheck --error-exitcode=1 $changed_files
	exit $?
fi

exit 0

如前面介绍,将此脚本保存为pre-commit文件,并保存到.git/hooks目录,并赋予可执行权限。那么在修改代码后,执行git commit就会自动调用cppcheck工具对代码进行检查了。

cppcheck更多用法,请参考CppCheck的官方Manual,或者网页版本官方Manual

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值