您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 
 订阅
C/C++ 静态代码检测工具cppcheck
 
 
   次浏览      
 2023-9-21
 
编辑推荐:
本文主要介绍了C/C++ 静态代码检测工具cppcheck。 希望能为大家提供一些参考或帮助。
文章来自于知乎,由火龙果Linda编辑推荐。

简介

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

主要选项

错误(error):这是最严重的问题,Cppcheck 100%确定这是错误。例如,数组越界,空指针解引用等。

警告(warning):Cppcheck认为代码看起来有问题,但它并不确定这是否真的是错误。例如,有可能发生整数溢出,有可能发生除以零的情况等。

样式(style):这些是关于代码风格的问题,例如未使用的函数、多余的代码等。

可移植性(portability):当代码在不同的平台上运行时可能会出现问题。例如,使用了不可移植的函数,或者依赖于编译器特定的行为。

性能(performance):Cppcheck会发出警告,如果代码可以优化以提高性能。

信息(information):这些是一些有趣的,非关键的信息,通常可以忽略。

这些选项可以通过命令行参数进行启用或禁用,以定制Cppcheck的行为。例如,如果你只关心错误和警告,你可以使用--enable=warning,error参数来运行Cppcheck。

检查范围

以下是 Cppcheck 的主要检查范围:

未定义行为:包括死指针、零除、整数溢出、无效的位移操作数、无效的转换、STL的无效使用、内存管理、空指针解引用、越界检查、未初始化的变量、写入const数据等。

安全性:Cppcheck 可以检测到一些常见的安全漏洞,如缓冲区错误、不当的访问控制、信息泄露等。

编码标准:Cppcheck 支持多种编码标准,包括 Misra C 2012、Misra C++ 2008、Cert C、Cert C++ 等。

其他检查:Cppcheck 还有许多其他的检查,具体可以参考 这个链接。

检查器

开启/关闭检查器

Cppcheck允许你通过命令行参数来启用或禁用特定的检查器。你可以使用--enable=参数来启用特定的检查器,或者使用--disable=参数来禁用特定的检查器。

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

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

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

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

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

默认检查器

Cppcheck的默认检查器包括:

错误(error):这类检查器主要检测可能导致程序崩溃或者运行不正常的问题,例如内存泄漏、数组越界、未初始化的变量等。

警告(warning):这类检查器主要检测可能导致程序表现不如预期的问题,但不一定会导致程序崩溃,例如未使用的函数、未使用的变量等。

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

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

获取检查器列表

你可以通过命令行应用程序获取所有已实现的检查器的当前列表:

取检查器列表

cppcheck --doc

 

获取错误消息列表

cppcheck --errorlist

内存泄漏相关检查

在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)、代码审查、测试等。

性能相关

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等。

安装

下面是在Linux和Windows下安装Cppcheck的步骤:

在Linux下安装Cppcheck

打开终端。

更新你的包列表。在Debian和Ubuntu上,你可以使用以下命令: bash sudo apt-get update 在Fedora上,你可以使用以下命令: bash sudo dnf update

安装Cppcheck。在Debian和Ubuntu上,你可以使用以下命令: bash sudo apt-get install cppcheck 在Fedora上,你可以使用以下命令: bash sudo dnf install cppcheck

验证安装。输入以下命令: bash cppcheck --version 如果Cppcheck已经成功安装,这个命令将会输出Cppcheck的版本信息。

在Windows下安装Cppcheck

访问Cppcheck的GitHub页面(https://github.com/danmar/cppcheck)。

点击“Releases”选项,然后下载最新版本的Cppcheck的Windows安装程序。

双击下载的安装程序文件,然后按照提示进行安装。

安装完成后,你可以在开始菜单中找到Cppcheck,或者在命令行中输入cppcheck来运行它。

注意:在Windows上,你可能需要将Cppcheck的安装目录添加到你的系统PATH中,以便在任何位置都可以运行Cppcheck。你可以在系统的环境变量设置中添加PATH。

自定义检测规则

方式一(过滤检测规则)

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

如果你想要忽略某些警告,可以在命令行中使用 --suppress 选项。例如,如果你想要忽略所有的“缺少头文件”的警告,可以使用以下命令:

cppcheck --suppress=missingInclude ./ 这里,“missingInclude” 是要忽略的警告类型。将其替换为您希望过滤掉的警告类型。

方式二(筛选检测结果)

在 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工具,获取其错误输出,然后根据一些自定义的规则来过滤错误信息。

方式三(--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可能会更高效。

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

在其他环境安装cppcheck插件

QtCreator

在Qt Creator中添加Cppcheck工具的步骤如下:

启动Qt Creator:首先,打开你的Qt Creator IDE。

打开工具选项:在菜单栏中,选择 "工具" -> "选项"。

进入外部工具设置:在弹出的选项窗口中,选择 "外部工具"。

添加新的外部工具:点击 "添加" 按钮,创建一个新的外部工具配置。

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

执行:输入你的Cppcheck执行文件的路径。例如,如果你在Linux下安装了Cppcheck,这个路径可能是 /usr/bin/cppcheck。在Windows下,这个路径可能是你的Cppcheck安装目录下的 cppcheck.exe 文件。

参数:输入 --enable=all %{CurrentProject:Path}。这个参数会让Cppcheck检查当前项目的所有代码,并启用所有的检查。

工作目录:输入 %{CurrentProject:Path}。这个设置会让Cppcheck在当前项目的目录下运行。

保存配置:点击 "应用" 或 "确定" 按钮,保存你的配置。

使用Cppcheck:现在,你可以在 "工具" -> "外部" -> "Cppcheck" 中运行Cppcheck了。

Visual Studio

以下是在Visual Studio 2019和2022中安装Cppcheck的步骤:

下载Cppcheck

首先,你需要下载Cppcheck。你可以从其官方GitHub页面(https://github.com/danmar/cppcheck)下载最新版本的Cppcheck。

安装Cppcheck

下载完成后,运行安装程序并按照提示进行安装。记住你安装Cppcheck的路径,因为你稍后需要在Visual Studio中使用它。

下载和安装Visual Studio插件

接下来,你需要下载并安装Cppcheck的Visual Studio插件。你可以从Visual Studio Marketplace(https://marketplace.visualstudio.com/items?itemName=MatthewManela.CppcheckforVisualStudio

)下载插件。在Visual Studio中,点击"Extensions"(扩展)菜单,然后选择"Manage Extensions"(管理扩展)。在打开的窗口中,点击"Online"(在线),然后在搜索框中输入"Cppcheck"。找到"Cppcheck for Visual Studio",点击"Download"(下载)。

下载完成后,重启Visual Studio以完成插件的安装。

配置Cppcheck

插件安装完成后,你需要配置Cppcheck。在Visual Studio中,点击"Tools"(工具)菜单,然后选择"Options"(选项)。在打开的窗口中,找到"Cppcheck",然后在"Cppcheck path"(Cppcheck路径)中输入你之前安装Cppcheck的路径。

使用Cppcheck

现在,你可以开始使用Cppcheck了。在Visual Studio中,右键点击你的项目,然后选择"Run Cppcheck"(运行Cppcheck)。Cppcheck将开始分析你的代码,并在"Error List"(错误列表)窗口中显示结果。

Vs code

在VS Code中安装和使用Cppcheck,你可以按照以下步骤操作:

下载并安装Cppcheck

首先,你需要下载并安装Cppcheck。你可以从其官方GitHub页面(https://github.com/danmar/cppcheck )下载最新版本的Cppcheck。下载完成后,运行安装程序并按照提示进行安装。记住你安装Cppcheck的路径,因为你稍后需要在VSCode中使用它。

安装Cppcheck插件

打开VS Code,点击左侧边栏的Extensions图标(或者使用快捷键Ctrl+Shift+X)打开Extensions视图。在搜索框中输入"Cppcheck",找到Cppcheck插件并点击Install按钮进行安装。

配置Cppcheck

插件安装完成后,你需要配置Cppcheck。点击左侧边栏的Settings图标(或者使用快捷键Ctrl+,)打开Settings视图。在搜索框中输入"Cppcheck",找到Cppcheck的设置项。在"Cppcheck Path"设置项中,输入你之前安装Cppcheck的路径。

使用Cppcheck

配置完成后,你可以开始使用Cppcheck了。在VS Code中,右键点击你的代码文件,然后选择"Run Cppcheck"。Cppcheck将开始分析你的代码,并在"Problems"窗口中显示结果。

检测示例

检测内存泄漏

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

 

在这段代码中,我们在main()函数中分配了一段内存,但在函数结束时没有释放。

然后,我们使用 Cppcheck 来检查这段代码。

cppcheck --enable=all memory_leak.cpp

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

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

检测空指针解引用

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

检测数组越界

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.

检测未使用的变量

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作为你的工具箱中的一个工具,而不是唯一的工具。

 

   
次浏览       
相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

最新活动计划
C++高级编程 12-25 [线上]
白盒测试技术与工具实践 12-24[线上]
LLM大模型应用与项目构建 12-26[特惠]
需求分析最佳实践与沙盘演练 1-6[线上]
SysML建模专家 1-16[北京]
UAF架构体系与实践 1-22[北京]
 
 
最新文章
.NET Core 3.0 正式公布:新特性详细解读
.NET Core部署中你不了解的框架依赖与独立部署
C# event线程安全
简析 .NET Core 构成体系
C#技术漫谈之垃圾回收机制(GC)
最新课程
.Net应用开发
C#高级开发技术
.NET 架构设计与调试优化
ASP.NET Core Web 开发
ASP.Net MVC框架原理与应用开发
成功案例
航天科工集团子公司 DotNet企业级应用设计与开发
日照港集 .NET Framewor
神华信 .NET单元测试
台达电子 .NET程序设计与开发
神华信息 .NET单元测试