C/C++ 静态代码检查工具cppCheck

C/C++ 静态代码检查工具cppCheckCppcheck 是一个用于 C C 代码的静态分析工具 它可以帮助开发者检测代码中的错误 Cppcheck 可以检测出许多类型的错误 包括语法错误 未使用的函数 内存泄漏 未初始化的变量等 Cp

大家好,欢迎来到IT知识分享网。

C/C++ 静态代码检查工具cppCheck_cppcheck自定义规则-CSDN博客

目录

    前言

    一、Windows安装cppCheck

        1.1 下载cppCheck

        1.2 安装cppCheck

        1.3 添加环境变量

        1.4 验证安装

    二、配置Qt外部工具–cppCheck

    三、使用Qt外部工具–cppCheck

    四、cppCheck参数说明

        4.1 主要选项

        4.2 检查范围

        4.3 检查器

        4.4 默认检查器

        4.5 获取检查器列表

        4.6 内存泄漏相关检查

        4.7 性能相关检查

    五、自定义检测规则

        5.1 方式一(过滤检测规则)

        5.2 方式二(筛选检测结果)

        5.3 方式三(–rule和–rule-file选项 增加正则表达式规则)

    六、检测示例

        6.1检测内存泄露

        6.2 检测空指针解引用

        6.3 检测数组越界

        6.4 检测未使用的变量

    七、Cppcheck的局限性


    前言

  • Cppcheck是一个用于C/C++代码的静态分析工具,它可以帮助开发者检测代码中的错误;
  • Cppcheck可以检测出许多类型的错误,包括语法错误、未使用的函数、内存泄漏、未初始化的变量等;
  • Cppcheck还支持用户自定义规则,这使得开发者可以根据自己的需求定制Cppcheck的行为;

    一、Windows安装cppCheck

        1.1 下载cppCheck

GitHub下载: GitHub – danmar/cppcheck: static analysis of C/C++ code 

C/C++ 静态代码检查工具cppCheck

C/C++ 静态代码检查工具cppCheck

        1.2 安装cppCheck

双击安装包,按照安装引导进行安装即可

C/C++ 静态代码检查工具cppCheck

        1.3 添加环境变量

C/C++ 静态代码检查工具cppCheck

        1.4 验证安装

 安装完成之后,可以通过以下方式调用:

  • 在开始菜单中找到Cppcheck;

C/C++ 静态代码检查工具cppCheck

  •  在命令行中输入cppcheck来运行;

C/C++ 静态代码检查工具cppCheck

    二、配置Qt外部工具–cppCheck

打开你的Qt Creator IDE,在菜单栏中,选择 【工具】 –> 【选项】

C/C++ 静态代码检查工具cppCheck

选择【环境】–>【外部工具】–>【添加】,外部工具

C/C++ 静态代码检查工具cppCheck

在新的外部工具配置中,填写以下信息:

  • 说明:工具说明,无特别要求;
  • 执行档:cppcheck的安装路径,C:\software\Cppcheck\cppcheck.exe;
  • 参数:–enable=all %{CurrentProject:Path},这个参数会让Cppcheck检查当前项目的所有代码,并启用所有的检查;
  • 工作目录:%{CurrentProject:Path},这个设置会让Cppcheck在当前项目的目录下运行;

保存配置:【Apply】–>【OK】

C/C++ 静态代码检查工具cppCheck
    三、使用Qt外部工具–cppCheck

 打开你的Qt Creator IDE,在菜单栏中,选择 【工具】 –> 【外部】–>【cppCheck】

C/C++ 静态代码检查工具cppCheck

C/C++ 静态代码检查工具cppCheck

    四、cppCheck参数说明

        4.1 主要选项

  • 错误(error):这是最严重的问题,Cppcheck 100%确定这是错误。例如,数组越界,空指针解引用等。
  • 警告(warning):Cppcheck认为代码看起来有问题,但它并不确定这是否真的是错误。例如,有可能发生整数溢出,有可能发生除以零的情况等。
  • 样式(style):这些是关于代码风格的问题,例如未使用的函数、多余的代码等。
  • 可移植性(portability):当代码在不同的平台上运行时可能会出现问题。例如,使用了不可移植的函数,或者依赖于编译器特定的行为。
  • 性能(performance):Cppcheck会发出警告,如果代码可以优化以提高性能。
  • 信息(information):这些是一些有趣的,非关键的信息,通常可以忽略。

这些选项可以通过命令行参数进行启用或禁用,以定制cppCheck的行为,例如:

  • 如果你只关心错误和警告,可以使用--enable=warning,error参数来运行cppCheck;

        4.2 检查范围

  • 未定义的行为:包括死指针、零除、整数溢出、无效的位移操作数、无效的转换、STL的无效使用、内存管理、空指针解引用、越界检查、未初始化的变量、写入const数据等。
  • 安全性:Cppcheck 可以检测到一些常见的安全漏洞,如缓冲区错误、不当的访问控制、信息泄露等。
  • 编码标准:Cppcheck 支持多种编码标准,包括 Misra C 2012、Misra C++ 2008、Cert C、Cert C++ 等。
  • 其他检查:Cppcheck 还有许多其他的检查,具体可以参考这个链接。

        4.3 检查器

开启检查器--enable=
关闭检查器--disable=

例如:如果只想启用内存相关的检查,可以使用一下命令:

cppcheck --enable=warning,performance,portability,information,missingInclude --suppress=missingIncludeSystem yourfile.cpp 

 这个命令将启用所有的警告,性能,可移植性,信息和缺失包含的检查,但是会抑制系统缺失包含的警告。

你可以在Cppcheck的官方手册中找到更多关于如何使用这些参数的信息。手册中详细介绍了每个参数的用途和如何使用它们。

请注意,你需要根据你的需求来选择启用或禁用哪些检查器。不是所有的检查器都适合所有的情况,所以你需要根据你的代码和你想要检查的问题来选择合适的检查器。

        4.4 默认检查器

 Cppcheck的默认检查器包括:

  • 错误(error):这类检查器主要检测可能导致程序崩溃或者运行不正常的问题,例如内存泄漏、数组越界、未初始化的变量等。
  • 警告(warning):这类检查器主要检测可能导致程序表现不如预期的问题,但不一定会导致程序崩溃,例如未使用的函数、未使用的变量等。

这两类检查器是默认启用的,无法被关闭。

对于其他的检查器,如样式(style)、性能(performance)、可移植性(portability)等,你可以通过–enable参数来启用或禁用。例如,如果你想启用所有的检查器,你可以使用–enable=all参数。

        4.5 获取检查器列表

  •  获取检查器列表
cppcheck --doc 
  •  获取错误消息列表
cppcheck --errorlist 

        4.6 内存泄漏相关检查

在Cppcheck中,内存泄漏检查是默认启用的。这意味着,即使你没有指定任何参数,Cppcheck也会检查内存泄漏。这是因为内存泄漏是一种严重的问题,所以Cppcheck默认总是检查它。

Cppcheck是一个静态分析工具,它可以检查C/C++代码中的多种类型的内存泄漏,包括但不限于:

  • 未释放的内存:当程序使用malloc、calloc、realloc或new分配内存,但没有使用free或delete释放它时,会发生内存泄漏。
  • 未关闭的文件:当程序使用fopen或其他函数打开文件,但没有使用fclose关闭它时,会发生资源泄漏,这也可以看作是一种特殊的内存泄漏。
  • 未释放的系统资源:当程序使用系统API分配资源(例如,使用socket函数创建套接字),但没有使用相应的函数释放它时,会发生资源泄漏。

然而,Cppcheck作为一个静态分析工具,它的检查是基于源代码的,而不是基于程序的运行状态。这意味着它有一些局限性:

  • 动态行为:Cppcheck可能无法准确地检测出由于程序的动态行为(例如,条件分支、循环、递归、并发等)导致的内存泄漏。
  • 复杂的数据结构:如果程序使用了复杂的数据结构(例如,链表、树、图等),并且内存管理逻辑也很复杂,Cppcheck可能无法准确地检测出内存泄漏。
  • 间接的内存泄漏:如果内存泄漏是通过间接的方式发生的(例如,通过函数指针、虚函数、回调函数等),Cppcheck可能无法检测出它。
  • 外部库和系统API:如果内存泄漏是由于错误使用外部库或系统API导致的,Cppcheck可能无法检测出它,除非这些库和API已经被Cppcheck的开发者显式地支持。

因此,虽然Cppcheck是一个非常有用的工具,但它不能替代其他类型的内存泄漏检查工具和技术,例如动态分析工具(如Valgrind)、代码审查、测试等。

        4.7 性能相关检查

 Cppcheck可以检查一些性能相关的问题。你可以通过以下命令来启用性能相关的检查:

cppcheck --enable=performance yourfile.cpp 

这个命令将启用性能相关的检查,不会启用其他的检查器。

性能检查可以帮助你找到可能影响代码运行效率的问题,例如未使用的变量,未使用的函数返回值,以及可能导致性能下降的编程模式等。

Cppcheck是一个静态分析工具,它可以检查C/C++代码中的各种问题,包括性能问题。以下是Cppcheck可以检查的一些性能问题类别:

  • 未使用的函数:如果代码中有未使用的函数,这可能会浪费内存和CPU资源。
  • 未使用的变量:同样,未使用的变量也可能会浪费内存。
  • 过度复杂的函数:如果一个函数过于复杂,它可能会导致CPU使用率过高。
  • 过大的栈使用:如果一个函数使用了过多的栈内存,这可能会导致栈溢出,从而导致程序崩溃。
  • 过度的循环:如果一个循环运行的次数过多,或者循环中的代码过于复杂,这可能会导致性能问题。

然而,Cppcheck的性能检查也有其局限性。以下是一些主要的局限性:

  • 静态分析的局限性:Cppcheck是一个静态分析工具,它只能检查代码的静态特性,不能检查运行时的性能问题。例如,它不能检查内存泄漏、CPU使用率过高、磁盘I/O过多等运行时的性能问题。
  • 不能检查算法效率:Cppcheck不能检查代码中使用的算法的效率。例如,如果你使用了一个O(n^2)的算法,而有一个O(n log n)的算法可以完成同样的任务,Cppcheck无法检测这个问题。
  • 不能检查并发问题:Cppcheck不能检查并发问题,例如死锁、竞态条件等。这些问题通常需要动态分析工具或专门的并发分析工具来检查。

如果你需要进行深入的性能分析,你可能需要使用专门的性能分析工具,如gprof,Valgrind的Callgrind,或者Intel VTune等。

    五、自定义检测规则

        5.1 方式一(过滤检测规则)

 使用--suppress选项过滤特定的警告:

  • 如果你想要忽略某些警告,可以在命令行中使用 –suppress 选项。
  • 例如,如果你想要忽略所有的“缺少头文件”的警告,可以使用以下命令:
  • cppcheck –suppress=missingInclude ./
  • “missingInclude” 是要忽略的警告类型。将其替换为您希望过滤掉的警告类型。

        5.2 方式二(筛选检测结果)

在 CppCheck 运行结束后,使用自定义脚本对输出结果进行过滤,例如:

可以使用 Python 编写一个脚本,读取 CppCheck 的输出,然后根据自定义规则筛选警告信息。

以下是一个简单的示例:

import subprocess import sys def main(): cppcheck_command = "cppcheck --enable=all --xml --xml-version=2 ./" result = subprocess.run(cppcheck_command.split(), capture_output=True, text=True) # 在这里添加自定义规则 def custom_filter(error): # 示例规则:过滤所有包含特定文件名的警告 return "my_special_file.cpp" not in error # 添加更多规则 def custom_filter_2(error): # 示例规则:过滤所有包含特定错误类型的警告 return "error type" not in error # 将所有规则放入一个列表中 filters = [custom_filter, custom_filter_2] # 对每个规则进行过滤 filtered_errors = result.stderr.splitlines() for filter_func in filters: filtered_errors = list(filter(filter_func, filtered_errors)) for error in filtered_errors: print(error) if __name__ == "__main__": main() 

 这段代码的主要步骤如下:

  • cppcheck_command = “cppcheck –enable=all –xml –xml-version=2 ./”:这行代码定义了一个字符串,这个字符串是要执行的命令。这个命令会调用cppcheck工具,–enable=all表示启用所有的检查,–xml表示输出结果为XML格式,–xml-version=2表示使用XML的版本2,./表示对当前目录下的所有文件进行检查。
  • result = subprocess.run(cppcheck_command.split(), capture_output=True, text=True):这行代码使用Python的subprocess模块来执行上面定义的命令。cppcheck_command.split()将命令字符串分割成一个列表,capture_output=True表示捕获命令的输出,text=True表示将输出作为文本处理。
  • custom_filter和custom_filter_2函数:这两个函数是自定义的过滤规则,它们都接收一个错误信息作为参数,如果错误信息满足某种条件(例如包含特定的文件名或错误类型),则返回False,否则返回True。这样就可以过滤掉不想看到的错误信息。
  • filters = [custom_filter, custom_filter_2]:这行代码将所有的过滤函数放入一个列表。
  • filtered_errors = result.stderr.splitlines():这行代码将cppcheck的错误输出分割成多行。
  • for filter_func in filters::这个循环对每个过滤函数进行迭代。
  • filtered_errors = list(filter(filter_func, filtered_errors)):这行代码使用Python的filter函数和当前的过滤函数来过滤错误信息。
  • 最后,对过滤后的错误信息进行迭代并打印。

 总的来说,这段代码的目的是运行cppcheck工具,获取其错误输出,然后根据一些自定义的规则来过滤错误信息。

        5.3 方式三(–rule和–rule-file选项 增加正则表达式规则)

cppcheck是一个C和C++代码的静态分析工具,它可以检查代码中的错误,包括语法错误、未使用的函数、内存泄漏、未初始化的变量等。cppcheck还支持用户自定义规则,这是通过–rule和–rule-file选项实现的。

–rule选项允许你直接在命令行中定义一个规则。规则是一个正则表达式,用于匹配你想要检查的代码模式。例如,如果你想检查所有的printf函数调用,你可以使用以下命令:

cppcheck --rule="printf" myfile.cpp 

 这将会检查myfile.cpp文件中所有的printf函数调用。

–rule-file选项允许你从一个文件中读取规则。这个文件应该包含一个或多个规则,每个规则一行。例如,如果你有一个名为rules.txt的文件,其中包含以下规则:

printf scanf 

 你可以使用以下命令应用这些规则:

cppcheck --rule-file=rules.txt myfile.cpp 

 这将会检查myfile.cpp文件中所有的printf和scanf函数调用。

注意,cppcheck的规则是正则表达式,所以你可以使用正则表达式的所有功能来定义你的规则。例如,你可以使用.*来匹配任何字符,[a-z]来匹配任何小写字母,等等。

最后,cppcheck的规则检查是大小写敏感的,所以printf和Printf是两个不同的规则。如果你想忽略大小写,你可以使用正则表达式的i标志,例如(?i)printf将会匹配printf、Printf、PRINTF等等。

rule自定义规则示例
以下是一些可能的Cppcheck自定义规则的例子:

  • 检查是否存在使用malloc而不是new的代码: bash malloc\( 这个规则会匹配到任何使用malloc函数的代码。在C++中,通常推荐使用new而不是malloc,因为new会自动调用对象的构造函数。
  • 检查是否存在使用printf而不是cout的代码: bash printf\( 这个规则会匹配到任何使用printf函数的代码。在C++中,通常推荐使用cout而不是printf,因为cout是类型安全的。
  • 检查是否存在未使用的变量: bash int\s+\w+; 这个规则会匹配到任何定义了一个整数变量但没有使用它的代码。未使用的变量可能是一个错误的信号,因为它可能意味着你忘记了使用这个变量。
  • 检查是否存在使用delete但没有将指针设为nullptr的代码: bash delete\s+\w+;\s*(?!.*\1\s*=\s*nullptr;) 这个规则会匹配到任何使用delete但没有将指针设为nullptr的代码。在C++中,删除一个指针后,通常推荐将其设为nullptr,以防止悬挂指针。
  • 检查是否存在没有虚析构函数的多态基类: bash class\s+\w+\s*{\s*(public|protected):\s*virtual\s+\w+\s*\(\)\s*;\s*(?!.*virtual\s+~\1\(\)\s*;) 这个规则会匹配到任何定义了虚函数但没有虚析构函数的类。在C++中,多态基类应该总是有一个虚析构函数,以防止在删除派生类对象时出现未定义的行为。
  • 检查是否存在使用std::endl而不是\n的代码: bash std::cout\s*<<\s*.*std::endl 这个规则会匹配到任何使用std::endl的代码。在C++中,std::endl不仅会插入一个换行符,还会刷新输出流。如果你不需要立即刷新输出流,使用\n可能会更高效。

请注意,这些规则可能会产生一些误报,因为它们可能会匹配到一些合法的代码。如果你需要更精确的检查,你可能需要创建一个更复杂的正则表达式,或者使用一个更高级的静态代码分析工具。

    六、检测示例

        6.1检测内存泄露

int main() { int *array = new int[100]; return 0; } 

 最后,Cppcheck 的输出可能类似下面这样:

Checking memory_leak.cpp... [Memory_leak.cpp:4]: (error) Memory leak: array 

        6.2 检测空指针解引用

int main() { int *ptr = nullptr; *ptr = 10; return 0; } 

 在这段代码中,我们创建了一个空指针ptr,然后试图对其进行解引用。这将导致未定义的行为。

我们可以使用Cppcheck来检查这段代码:

cppcheck --enable=all null_pointer.cpp 

Cppcheck的输出可能类似下面这样:

Checking null_pointer.cpp... [null_pointer.cpp:3]: (error) Null pointer dereference: ptr 

        6.3 检测数组越界

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

 在这段代码中,我们试图访问数组的第11个元素,但数组的大小只有10。这将导致未定义的行为。

我们可以使用Cppcheck来检查这段代码:

cppcheck --enable=all array_out_of_bounds.cpp 

 Cppcheck的输出可能类似下面这样:

Checking array_out_of_bounds.cpp... [array_out_of_bounds.cpp:3]: (error) Array 'array[10]' accessed at index 10, which is out of bounds. 

        6.4 检测未使用的变量

int main() { int unused = 0; return 0; } 

 在这段代码中,我们声明了一个变量unused,但没有在任何地方使用它。

我们可以使用Cppcheck来检查这段代码:

cppcheck --enable=all unused_variable.cpp 

 Cppcheck的输出可能类似下面这样:

Checking unused_variable.cpp... [unused_variable.cpp:2]: (style) Unused variable: unused 

 这些只是Cppcheck可以检测的一些错误类型的示例。Cppcheck还可以检测许多其他类型的错误和潜在问题。

    七、Cppcheck的局限性

 Cppcheck是一个非常有用的工具,它可以检测C++代码中的许多常见错误和潜在问题。然而,像所有工具一样,Cppcheck也有其局限性。以下是一些主要的局限性:

  • 无法检测所有类型的错误:虽然Cppcheck可以检测许多类型的错误,但它不能检测所有类型的错误。例如,它无法检测逻辑错误,这种错误只能通过仔细的代码审查和测试来发现。
  • 可能存在误报和漏报:Cppcheck可能会误报一些不存在的问题,或者漏报一些实际存在的问题。这是因为Cppcheck主要依赖于静态分析,而静态分析的准确性受到许多因素的影响,包括代码的复杂性、使用的编程语言特性等。
  • 无法处理非标准的C++特性:Cppcheck是基于标准C++的,因此,如果你的代码使用了非标准的C++特性,Cppcheck可能无法正确处理。
  • 无法理解复杂的语义:Cppcheck主要通过语法和简单的语义分析来检测错误,但它无法理解复杂的语义。例如,如果一个函数的行为依赖于它的输入参数的某些特性,Cppcheck可能无法正确理解这种依赖关系。
  • 无法分析运行时行为:Cppcheck是一个静态分析工具,它只能分析代码的文本,而不能分析代码的运行时行为。因此,它无法检测运行时错误,如竞态条件、死锁等。
  • 无法分析动态内存管理:虽然Cppcheck可以检测一些基本的内存管理错误,如内存泄漏,但它无法分析复杂的动态内存管理问题,如内存碎片化。
  • 无法分析库函数的行为:Cppcheck无法分析库函数的内部行为。因此,如果你的代码依赖于库函数的某些特性,Cppcheck可能无法正确检测相关的问题。

总的来说,虽然Cppcheck是一个非常有用的工具,但它不能替代其他的代码审查和测试工具。你应该将Cppcheck作为你的工具箱中的一个工具,而不是唯一的工具。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/120722.html

(0)
上一篇 2025-10-27 21:33
下一篇 2025-10-27 22:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信