天天看點

Cppcheck 用法(上篇)

簡述

Cppcheck 是一種 C/C++ 代碼缺陷靜态檢查工具。不同于 C/C++ 編譯器及很多其它分析工具,它不檢查代碼中的文法錯誤。Cppcheck 隻檢查編譯器檢查不出來的 bug 類型,其目的是檢查代碼中真正的錯誤(即:零誤報)。

| 版權聲明:一去、二三裡,未經部落客允許不得轉載。

介紹

支援的代碼和平台:

  • 可以檢查非标準代碼,包括不同的編譯器擴充、内聯彙編代碼等。
  • Cppcheck 應該被處理最新 C++ 标準的任何 C++ 編譯器所編譯。
  • Cppcheck 應該在任何有足夠 CPU 和記憶體的平台上工作。

要知道 Cppcheck 有限制,Cppcheck 很少在報告錯誤方面出錯,但有很多 bug,它不能檢測。

通過仔細測試軟體,你會發現軟體中有更多的 bug,而不是使用 Cppcheck。但 Cppcheck 仍可以檢測到在測試和評估軟體時錯過的一些 bug。

開始使用

第一個測試程式

這裡有一段簡單的代碼:

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

将代碼儲存進 file.c 檔案中,執行:

cppcheck file.c      

注意:執行此指令前,需要将 cppcheck.exe 所在路徑添加至環境變量 PATH 中。

這時,将會從 cppcheck 中輸出:

Checking file.c …

[file.c:4]: (error) Array ‘a[10]’ accessed at index 10, which is out of bounds.

檢查檔案夾中的所有檔案

通常一個項目會有許多源檔案,如果需要同時檢查,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

手動檢查檔案或使用項目檔案

使用 Cppcheck 可以手動檢查檔案,通過指定檔案/檔案夾來檢查和設定,或者可以使用一個工程檔案(cmake/visual studio)。

使用項目檔案更快,因為它隻需要非常少的配置。

手動檢查檔案可以更好的控制分析。

不一定哪種方法會有最好的結果,建議嘗試一下,可能會得到不同的結果,發現大多數 bug 需要使用這兩種方法。

檢查時排除某個檔案或檔案夾

排除一個檔案或檔案夾有兩個選項,第一個選項是隻提供你想檢查的路徑和檔案:

cppcheck src/a      

所有位于 src/a 和 src/b 下的檔案都會被檢查。

方式二:使用 ​

​-i​

​ 選項

這時,将會忽略指定的檔案/檔案夾,使用下面指令在 src/c 将不會被檢查:

cppcheck -isrc/c src      

嚴重性

可能的嚴重性消息有:

  • 錯誤

    當發現 bug 時使用

  • 警告

    關于防禦性程式設計,以防止 bug 的建議

  • 風格警告

    風格有關問題的代碼清理(未使用的函數、備援代碼、常量性等等)

  • 可移植性警告

    可移植性警告。64 位的可移植性,代碼可能在不同的編譯器中運作結果不同。

  • 性能警告

    建議使代碼更快。這些建議隻是基于常識,即使修複這些消息,也不确定會得到任何可測量的性能提升。

  • 資訊消息

    配置問題,建議在配置期間僅啟用這些。

啟用消息

預設情況下,隻顯示錯誤消息,可以通過 ​

​--enable​

​ 指令啟用更多檢查。

啟用警告消息:

cppcheck --enable=warning file.c      

啟用性能消息:

cppcheck --enable=performance file.c      

啟用資訊消息:

cppcheck --enable=information file.c      

由于曆史原因 ​

​--enable=style​

​ 可以啟用警告、性能、可移植性和樣式資訊。當使用舊 XML 格式時,這些都由 style 表示:

cppcheck --enable=style file.c      

啟用警告和性能消息:

cppcheck --enable=warning,performance file.c      

啟用 unusedFunction 檢查。這不能通過 ​

​--enable=style​

​ 啟用,因為不會在庫中正常工作。

cppcheck --enable=unusedFunction file.c      

啟用所有消息:

cppcheck --enable=all      

不确定消息

預設情況下,如果确定,Cppcheck 隻顯示錯誤消息。如果使用 ​

​--inconclusive​

​,當分析不确定時,也會寫錯誤消息。

cppcheck --inconclusive path      

這當然會導緻錯誤的警告,即使在沒有 bug 的情況下,也可能會報 bug。如果可以接受錯誤的警告,可以使用此指令。

儲存結果到檔案中

很多時候,會希望将結果儲存在一個檔案中,可以使用 shell 的管道重定向錯誤輸出到一個檔案:

cppcheck file.c 2> err.txt      

多線程檢查

選項 ​

​-j​

​ 用于指定需要使用的線程數,例如,使用 4 個線程檢查檔案夾中的檔案:

cppcheck -j 4      

注意:這将禁用 unusedFunction 檢查。

平台

應該使用一個與你的目标比對的平台配置。

預設情況下,如果代碼在本地編譯和執行,Cppcheck 會使用本地平台配置。

Cppcheck 具有用于 Unix 和 Windows 目标的内置配置,可以輕松地使用這些 ​

​--platform​

​ 指令行标志。

還可以在 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>      

項目

當使用 CMake 或 Visual Studio 時,可以使用 ​

​--project​

​ 來分析項目。

它會給你快速和簡單的結果,不需要做太多的配置。但很難說這是否将會給你最好的結果,建議試一試它,并嘗試不使用 ​

​--project​

​ 分析源代碼,看哪個選項更适合。

CMake

Cppcheck 可以了解編譯資料庫,可以用 CMake 生成這些。

例如:

$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON      

檔案 compile_commands.json 在目前檔案夾中建立。

現在像這樣運作 Cppcheck:

$ cppcheck --project=compile_commands.json      

Visual Studio

可以對單個項目檔案(​

​*.vcxproj​

​​)或整個解決方案(​

​*.sln​

​)運作 Cppcheck。

在整個解決方案上運作 cppcheck:

$ cppcheck --project=foobar.sln      

在單個項目檔案上運作 cppcheck:

$ cppcheck --project=foobar.vcxproj      

注意:還有一個 Visual Studio 插件,允許在 Visual Studio 中運作 cppcheck。

預處理器設定

如果使用 ​

​--project​

​,那麼 Cppcheck 将使用項目檔案中的預處理器設定。

否則,可能需要配置包含路徑,定義等。

定義

這有一個檔案,有兩個配置(定義和沒定義 A):

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

預設情況下,Cppcheck 将檢查所有預處理器配置(除了那些具有 #error 的配置),是以上述代碼将被分析在當 A 定義和不定義的情況下。

可以使用 ​

​-D​

​​ 更改。當使用 ​

​-D​

​​ 時,cppcheck 将預設隻檢查給定的配置,不會檢查其它,這就是編譯器的工作原理。但是可以使用 ​

​--force​

​​ 或 ​

​--max-configs​

​ 來覆寫配置數量。

檢查所有配置:

cppcheck file.c      

隻檢查配置 A:

cppcheck -DA file.c      

當定義宏 A 時,檢查所有配置:

cppcheck -DA --force file.c      

另一個有用的标志可能是 ​

​-U​

​,它未定義符号。 用法示例:

cppcheck -UX file.c      

這意味着 X 沒有定義,Cppcheck 不會檢查當定義 X 時會發生什麼。

XML 輸出

Cppcheck 可以生成 XML 格式的輸出。有一個舊的 XML 格式(version 1)和一個新的 XML 格式(version 2)。如果可以,請使用新版本。

舊版本保持向後相容性。它不會改變,但有一天可能會被删除。使用 ​

​--xml​

​ 支援這種格式。

新版本修複一些舊格式的問題。新格式可能會在 cppcheck 的未來版本中更新,并帶有新的屬性和元素。用于檢查檔案并以新的 XML 格式輸出錯誤的示例指令:

cppcheck --xml-version=2 file.cpp      

這是一個 version 2 示例:

<?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>      

元素

每個錯誤都在 ​

​<error>​

​ 元素中,屬性:

  • id

    錯誤的 id,這些都是有效的符号名稱。

  • severity

    error、warning、style、performance、portability、information 中的任何一個。

  • msg

    短格式的錯誤消息

  • verbose

    長格式的錯誤消息

  • inconclusive

    此屬性僅在消息不确定時使用

  • cwe

    消息的 CWE ID,此屬性僅在消息的 CWE ID 已知時使用。

元素

​<location>​

​ 元素列出所有錯誤相關位置,首先列出主要位置。

屬性:

  • file

    檔案名,相對路徑和絕對路徑都是可能的。

  • file0

    源檔案的名稱(可選)

  • line

    一個數字

  • msg

    此屬性尚不存在,但将來可以為每個位置添加一條短消息。

格式化輸出

如果想重新格式化輸出,使它看起來不同,可以使用模闆。

要獲得 Visual Studio 相容的輸出,可以使用 ​

​--template=vs​

​:

cppcheck --template=vs gui/test.cpp      

輸出将如下所示:

Checking gui/test.cpp…

gui/test.cpp(31): error: Memory leak: b

gui/test.cpp(16): error: Mismatching allocation and deallocation: k

要獲得 gcc 相容的輸出,可以使用 ​

​--template=gcc​

​:

cppcheck --template=gcc gui/test.cpp      

輸出将如下所示:

Checking gui/test.cpp…

gui/test.cpp:31: error: Memory leak: b

gui/test.cpp:16: error: Mismatching allocation and deallocation: k

可以編寫自己的模式(例如,逗号分隔格式):

cppcheck --template="{file},{line},{severity},{id},{message}"      

輸出将如下所示:

Checking gui/test.cpp…

gui/test.cpp,31,error,memleak,Memory leak: b

gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocation: k

  • callstack

    調用棧 - 如果可用

  • file

    檔案名

  • id

    消息 id

  • line

    行号

  • message

    詳細的消息文本

  • severity

    一個消息的類型/等級

更多參考

  • ​​Cppcheck​​

繼續閱讀