簡述
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