微服務管理平臺nacos虛擬ip負載均衡集群模式搭建
3463
2025-03-31
【Clang】
Clang是C、C++、Objective-C和Objective-C++編程語言,以及OpenMP、OpenCL、RenderScript、CUDA和HIP框架的編譯器前端。它使用LLVM編譯器基礎設施作為后端,自LLVM 2.6以來,一直是LLVM發布周期的一部分。
它被設計為GNU編譯器集(GCC)的替代者,支持大部分的編譯標志和非官方語言擴展。它的貢獻者包括蘋果、微軟、谷歌、ARM、索尼、英特爾和高級微設備(AMD)。它是一個開放源碼軟件,源代碼是在伊利諾伊大學/NCSA許可證下發布的,這是一個自由軟件許可證。從v9.0.0版本開始,它被重新授權到Apache License 2.0版本(LLVM除外)。
Clang項目包括Clang前端,一個靜態分析器和幾個代碼分析工具。
【背景】
從2005年開始,蘋果公司在許多商業產品中廣泛使用了LLVM,其中包括iOS SDK和Xcode 3.1。
LLVM最初是使用GCC的前端的,但GCC結果給LLVM的開發者和Apple公司帶來了一些問題。GCC源碼對開發者來說是一個龐大且有些繁瑣的系統;正如一位長期使用GCC的開發者在談到LLVM時所說的那樣,"試圖讓河馬起舞其實并沒有多少樂趣"。
蘋果軟件大量使用了Objective-C,但GCC中的Objective-C前端對于GCC開發者來說,其優先級較低。另外,GCC并不能順利地集成到蘋果公司的集成開發環境(IDE)中。最后,GCC是根據GNU General Public License (GPL)?版本3的條款授權的,它要求發布GCC的擴展或修改版本的開發者必須提供他們的源代碼,而LLVM有一個類似BSD的許可證,沒有這樣的要求。
蘋果公司選擇從頭開始開發一個新的編譯器前端,支持C、Objective-C和C++。這個?"clang "項目是在2007年7月開源的。
【設計】
Clang的目的是在LLVM之上工作。Clang和LLVM的結合提供了大部分的工具鏈,可以替代完整的GCC堆棧。因為它是基于庫的設計,就像LLVM的其他部分一樣,Clang很容易嵌入到其他應用中。這也是大多數OpenCL實現都是用Clang和LLVM構建的原因之一。
Clang的主要目標之一是提供一個基于庫的架構,并且讓編譯器與源代碼交互的工具,如集成開發環境(IDE)圖形用戶界面(GUI)等更緊密地結合在一起。相比之下,GCC被設計成了編譯-鏈接-調試的工作流程,要將其與其他工具集成起來并不容易。例如,GCC使用了一個叫做fold的步驟,這個步驟是整個編譯過程的關鍵,它的副作用是將代碼樹翻譯成與原始源碼不同的形式。如果在fold步驟期間或之后發現了錯誤,要將其翻譯回原始源碼中的一個位置可能會很困難。另外,在IDE中使用GCC堆棧的廠商會使用單獨的工具來索引代碼,提供語法高亮和自動完成等功能。
與GCC相比,Clang的設計目的是在編譯過程中保留更多的信息,并保留原始代碼的整體形式。這樣做的目的是為了更容易將錯誤映射回原始源碼。Clang提供的錯誤報告也是為了更詳細、更具體,以及機器可讀,因此IDE可以在編譯過程中對編譯器的輸出進行索引。編譯器的模塊化設計可以提供源代碼索引、語法檢查以及其他通常與快速應用程序開發系統相關的功能。解析樹也更適合于支持自動代碼重構,因為它直接表示原始源代碼。
Clang只編譯類似C的編程語言,如C、C++、Objective-C、Objective-C++、OpenCL、CUDA和HIP。對于其他語言,如Ada,LLVM仍然依賴于GCC或其他編譯器前端。在很多情況下,Clang可以根據需要使用或換成GCC,對整個工具鏈沒有其他影響。它支持大多數常用的GCC選項。Nvidia和The Portland Group的一個子項目Flang增加了對Fortran的支持。
【性能和GCC兼容性】
Clang的設計是為了與GCC高度兼容。Clang的命令行界面與GCC相似,并與GCC共享許多標志和選項。Clang實現了許多GNU語言的擴展,并在默認情況下啟用了它們。Clang?實現了許多?GCC?編譯器的內在性。例如,盡管?Clang?實現了與?C11?原子內含函數完全對應的原子內含函數,但為了與?GCC?和?libstdc++?兼容,它也實現了?GCC?的?__sync_*?內含函數。Clang還保持了與GCC生成的對象代碼的ABI兼容性。在實際應用中,Clang經常可以作為GCC的替代方案。
與GCC等競爭性編譯器相比,Clang的開發者旨在減少內存占用,提高編譯速度。2007年10月,他們報告說,Clang編譯Carbon庫的速度是GCC的兩倍多,而使用的內存和磁盤空間只有GCC的六分之一。截至2014年中期,Clang贏得了超過三分之一的基準測試,其中GCC贏得了大部分。截至2014年,Clang編譯的程序的性能落后于GCC編譯的程序,有時性能差出很多(高達5.5倍),這也重復了之前關于性能變慢的報告。
2016年11月更多的比較表明,這兩個編譯器都為了提高性能而做了改進。截止到GCC 4.8.2與clang 3.4的對比,在大量的測試文件上,GCC在優化好的源碼上性能優于clang約17%。測試結果是針對特定代碼的,未經優化的C源代碼則正好相反。這兩個編譯器在性能上現在看起來大致上是旗鼓相當的。
【特點和目標】
該項目的一些目標包括:
終端用戶功能:
l??快速編譯和低內存使用
l??表現力強的診斷(示例)
l??GCC的兼容性
【使用案例】
Windows+vscode+clang
clang --version
#include?
#include?
void?f(int?*g)?{
printf("%x",?(int)g);
}
int?main()?{
int?*p;
p?=?(int?*)malloc(10?*?sizeof(int));
f(p);
free(p);
return?0;
}
#include?
#include?
#include?
using?namespace?std;
int?main()
{
vector
for?(const?string&?word?:?msg)
{
cout?<
}
cout?<
}
{
//?See?https://go.microsoft.com/fwlink/?LinkId=733558
//?for?the?documentation?about?the?tasks.json?format
"version":?"2.0.0",
"tasks":?[
{
"type":?"shell",
"label":?"clang?build?active?file",
"command":?"clang",
"args":?[
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options":?{
"cwd":?"${workspaceFolder}"
},
"problemMatcher":?["$gcc"],
"group":?{
"kind":?"build",
"isDefault":?true
}
}
]
}
列號和齒條診斷
clang生成的所有診斷程序都包括完整的列號信息。clang的命令行編譯器驅動程序使用這些信息來打印?"點診斷"。(IDE可以使用這些信息來顯示行內錯誤標記。)?它可以讓你很容易理解某個特定代碼中的問題所在。
這個點(綠色的"^"字符)準確地顯示了問題所在,即使是在字符串內部。這讓我們可以很容易地跳轉到問題所在,并且在一行中出現多個相同字符的實例時也很有幫助。
$?clang -fsyntax-only format-strings.c
format-strings.c:91:13:?warning:?'.*' specified field precision is missing a matching 'int' argument
printf("%.*d");
^
請注意,現代版本的?GCC?跟隨?Clang?的思路,現在能夠給出一個診斷列,并在結果中包含一段源文本的片段。然而,Clang?的列號更準確,它指向的是有問題的格式指定器,而不是解析器在檢測到問題時到達的?)?字符。另外,Clang的診斷結果默認是彩色的,這樣更容易與附近的文本區分開來。
相關文本的范圍高亮顯示
Clang可以捕捉并準確地跟蹤你的程序中的表達式、語句和其他構造物的范圍信息,并利用這些信息來進行診斷,以突出顯示相關信息。在下面這個例子中,你可以不需要看原始的源代碼,就可以根據Clang的錯誤來理解是什么地方出了問題。因為clang會打印出一個點,你可以清楚地知道它抱怨的是哪個加號。范圍信息突出顯示了加號的左右兩邊,問題出在哪里,一目了然。范圍信息對于涉及優先級問題和許多其他情況下非常有用。
$?gcc-4.9?-fsyntax-only?t.c
t.c:?In?function?'int?f(int,?int)':
t.c:7:39:?error:?invalid?operands?to?binary?+?(have?'int'?and?'struct?A')
return?y?+?func(y???((SomeA.X?+?40)?+?SomeA)?/?42?+?SomeA.X?:?SomeA.X);
^
$?clang?-fsyntax-only?t.c
t.c:7:39:?error:?invalid?operands?to?binary?expression?('int'?and?'struct?A')
return?y?+?func(y???((SomeA.X?+?40)?+?SomeA)?/?42?+?SomeA.X?:?SomeA.X);
~~~~~~~~~~~~~~?^?~~~~~
精確的措辭
在下面的例子中,不僅告訴你*有問題,還準確地告訴你為什么,并告訴你類型是什么(如果是一個復雜的子表達式,比如調用一個超載函數)。這種對細節的關注使我們更容易理解和快速修復問題。
$?gcc-4.9?-fsyntax-only?t.c
t.c:5:11:?error:?invalid?type?argument?of?unary?'*'?(have?'int')
return?*SomeA.X;
^
$?clang?-fsyntax-only?t.c
t.c:5:11:?error:?indirection?requires?pointer?operand?('int'?invalid)
int?y?=?*SomeA.X;
^~~~~~~~
類型預留
下面的例子說明了在C語言中保存一個類型定義是很重要的。
$?clang?-fsyntax-only?t.c
t.c:15:11:?error:?can't?convert?between?vector?values?of?different?size?('__m128'?and?'int?const?*')
myvec[1]/P;
~~~~~~~~^~
下面的例子顯示了編譯器在哪些地方可以揭示一個?類型定義的底層細節。如果用戶對pid_t存有疑惑,clang會貼心的顯示“aka”
$?clang?-fsyntax-only?t.c
t.c:13:9:?error:?member?reference?base?type?'pid_t'?(aka?'int')?is?not?a?structure?or?union
myvar?=?myvar.x;
~~~~~?^
在C++中,類型保存包括保留寫到類型名中的任何限定。比如說:
namespace?services?{
struct?WebService?{??};
}
namespace?myapp?{
namespace?servers?{
struct?Server?{??};
}
}
using?namespace?myapp;
void?addHTTPService(servers::Server?const?&server,?::services::WebService?const?*http)?{
server?+=?http;
}
對上面代碼進行編譯,Clang既提供了準確的信息,又保留了用戶所寫的類型(例如,"servers:::Server"、"::services:::WebService")。
$?clang?-fsyntax-only?t.cpp
t.cpp:9:10:?error:?invalid?operands?to?binary?expression?('servers::Server?const'?and?'::services::WebService?const?*')
server?+=?http;
~~~~~~?^??~~~~
當然,類型保存也可以擴展到模板的使用,Clang保留了關于特定模板特殊化(如?std:::vector
$?clang?-fsyntax-only?t.cpp
t.cpp:12:7:?error:?incompatible?type?assigning?'vector
str?=?vec;
^?~~~
修復提示
修復提示為修復源代碼中的小問題提供了建議。當Clang產生了一個診斷結果時,如果它可以解決某個特定問題(例如,非標準或多余的語法、缺失的關鍵字、常見的錯誤等)。它會以代碼轉換的形式提供具體的指導,以糾正問題。在下面的例子中,Clang警告了一個自1993年以來被認為已經過時的GCC擴展的使用。應將下劃線的代碼去掉,然后替換成點行下面的代碼(".x="或".y=")。
$?clang?t.c
t.c:5:28:?warning:?use?of?GNU?old-style?field?designator?extension
struct?point?origin?=?{?x:?0.0,?y:?0.0?};
~~?^
.x?=
t.c:5:36:?warning:?use?of?GNU?old-style?field?designator?extension
struct?point?origin?=?{?x:?0.0,?y:?0.0?};
~~?^
.y?=
"修復?"提示對于解決用戶常見的錯誤和誤解是最有用的。例如,C++用戶通常會忘記類模板顯式化的語法,就像下面這個例子中的錯誤。同樣,在描述了問題之后,Clang提供了修復方法—添加模板<>--作為診斷的一部分。
$?clang?t.cpp
t.cpp:9:3:?error:?template?specialization?requires?'template<>'
struct?iterator_traits
^
template<>
模板類型差異
模板類型會比較長,難于閱讀。當出現在錯誤信息的一部分時,就更難理解了。Clang并不只是打印出類型名稱,而是會突出顯示不同之處。為了更清楚地顯示模板結構,模板類型也可以以縮進式文本樹的形式打印出來。
t.cc:4:5:?note:?candidate?function?not?viable:?no?known?conversion?from?'vector
t.cc:4:5:?note:?candidate?function?not?viable:?no?known?conversion?from?'vector
t.cc:4:5:?note:?candidate?function?not?viable:?no?known?conversion?for?1st?argument;
vector<
map<
[...],
[float?!=?double]>>
t.cc:4:5:?note:?candidate?function?not?viable:?no?known?conversion?for?1st?argument;
vector<
map<
int,
[float?!=?double]>>
自動宏擴展
很多錯誤都是在宏中發生的,而這些錯誤有時是深度嵌套的。使用傳統的編譯器,你需要深入挖掘宏的定義,才能了解自己是如何陷入困境的。下面這個簡單的例子展示了Clang是如何通過宏實例化時自動打印出實例化信息和嵌套范圍信息來診斷的,并在一個更大的例子中展示了一些其他部分是如何工作的。
$?clang?-fsyntax-only?t.c
t.c:80:3:?error:?invalid?operands?to?binary?expression?('typeof(P)'?(aka?'struct?mystruct')?and?'typeof(F)'?(aka?'float'))
X?=?MYMAX(P,?F);
^~~~~~~~~~~
t.c:76:94:?note:?expanded?from:
#define?MYMAX(A,B)????__extension__?({?__typeof__(A)?__a?=?(A);?__typeof__(B)?__b?=?(B);?__a?
~~~?^?~~~
下面是另一個發生在?"window "Unix程序包(實現了?"wwopen "類的API)中的現實警告。
$?clang?-fsyntax-only?t.c
t.c:22:2:?warning:?type?specifier?missing,?defaults?to?'int'
ILPAD();
^
t.c:17:17:?note:?expanded?from:
#define?ILPAD()?PAD((NROW?-?tt.tt_row)?*?10)????/*?1?ms?per?char?*/
^
t.c:14:2:?note:?expanded?from:
register?i;?\
^
運行質量和對細節的關注
$?cat?t.cc
template
class?a?{};
struct?b?{}
a
$?gcc-4.9?t.cc
t.cc:4:8:?error:?invalid?declarator?before?'c'
a
^
$?clang?t.cc
t.cc:3:12:?error:?expected?';'?after?struct
struct?b?{}
^
;
下面的例子表明,即使在GCC無法應對的復雜情況下,clang也能很好地診斷和恢復缺失的類型名關鍵詞。
$?cat?t.cc
template
struct?A?{?};
void?g()
{
A?a;
f(a);
}
$?gcc-4.9?t.cc
t.cc:1:33:?error:?variable?or?field?'f'?declared?void
template
^
t.cc:?In?function?'void?g()':
t.cc:6:5:?error:?'f'?was?not?declared?in?this?scope
f(a);
^
t.cc:6:8:?error:?expected?primary-expression?before?'>'?token
f(a);
^
$?clang?t.cc
t.cc:1:26:?error:?missing?'typename'?prior?to?dependent?type?name?'T::type'
template
^~~~~~~
typename
t.cc:6:5:?error:?no?matching?function?for?call?to?'f'
f(a);
^~~~
t.cc:1:24:?note:?candidate?template?ignored:?substitution?failure?[with?T?=?A]:?no?type?named?'type'?in?'A'
template
^????~~~~
【官方網站】
https://clang.llvm.org/
【最新版本】
10.0.0于2020年3月24日
【License】
Apache License 2.0?(LLVM除外)
【Clang-tidy】
clang-tidy是一個基于clang的C++"linter "工具。它的目的是提供一個可擴展的框架,用于診斷和修復典型的編程錯誤,如樣式違規、界面錯誤或通過靜態分析推導出的BUG。
【用法】
clang-tidy是一個基于LibTooling的工具。你也可以在命令行中在---之后指定編譯選項。
clang-tidy?test.cpp?--?-Imy_project/include?-DMY_DEFINES?...
clang-tidy有自己的檢查,也可以運行Clang靜態分析器的檢查。每個檢查都有一個名字,可以使用?-checks=?選項來選擇要運行的檢查,它指定了一個由正數和負數(前綴為-)globs組成的逗號分隔的列表。正的globs會添加檢查的子集,負的globs會刪除它們。例如:
clang-tidy?test.cpp?-checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus*
以上命令將禁用所有默認檢查?(-*)?并啟用所有?clang-alyanzer-*?檢查,但?clang-alyanzer-cplusplus*?檢查除外。
-list-checks?選項列出了所有已啟用的檢查。如果不使用?-checks=,它將顯示默認啟用的檢查。使用?-checks=*?來查看所有可用的檢查,或者使用?-checks=?的任何其他值來查看該值所啟用的檢查。
目前有以下幾組檢查內容:
名稱前綴
描述
abseil-
與Abseil程序庫相關的檢查
android-
與Android相關的檢查
boost-
與Boost程序庫相關的檢查.
bugprone-
檢查容易出現錯誤的目標代碼構造
cert-
與CERT安全編碼指南相關的檢查。
clang-analyzer-
Clang靜態分析檢查。
cppcoreguidelines-
與C++核心指南相關的檢查。
darwin-
與達爾文編碼公約相關的檢查。
fuchsia-
檢驗相關的Fuchsia編碼慣例。
google-
與谷歌編碼公約相關的檢查。
hicpp-
高完整性C++編碼標準的相關檢查。
linuxkernel-
與Linux內核編碼公約相關的檢查。
llvm-
與LLVM編碼公約有關的檢查。
llvmlibc-
與LLVM-libc編碼標準相關的檢查。
misc-
雜類標準檢查
modernize-
對現代(目前?"現代?"是指?"C++11")語言結構的檢查。
mpi-
與MPI(信息傳遞接口)相關的檢查。
objc-
與Objective-C編碼慣例相關的檢查。
openmp-
與OpenMP API相關的檢查。
performance-
針對性能相關問題的檢查。
portability-
針對與任何特定編碼風格無關的可移植性相關問題進行檢查。
readability-
針對與任何特定編碼風格無關的可讀性相關問題進行檢查。
zircon-
與Zircon內核編碼公約相關的檢查。
Clang診斷程序的處理方式與檢查診斷程序類似。Clang診斷程序由clang-tidy顯示,可以使用-checks=選項過濾掉。但是,-checks=選項并不影響編譯參數,所以它不能打開Clang警告,也就是說這些警告在編譯配置中沒有打開。-warnings-as-errors=?選項會將在?-checks=?選項下發出的警告升級為錯誤(但它本身不會啟用任何檢查)。
Clang?診斷程序的檢查名稱以?clang-diagnostic-開頭。有相應的警告選項的診斷程序被命名為?clang-diagnostic-
如果有相應的檢查支持,-fix標志會指示clang-tidy修復發現的錯誤。
所有命令行選項可用如下命令顯示:
clang-tidy?--help
【抑制不希望的診斷】
clang-tidy診斷的目的是查出不符合編碼標準的代碼,或者在其他方面有問題的代碼。但是,如果已知的代碼是正確的,則有必要消除警告。有些clang-tidy檢查提供了特定的檢查方式來消除診斷,比如bugpron-use-after-move后的變量可以通過在變量被移出后重新初始化來消除警告,bugpron-string-integer-assignment可以通過顯式轉換將整數轉換為char來抑制,可讀性-implicit-bool-conversion也可以通過顯式轉換來抑制等等。
如果特定的壓制機制對某一警告不適用,或者由于某種原因不希望使用它,clang-tidy有一個通用的機制,可以使用NOLINT或NOLINTNEXTLINE注釋來壓制診斷。
NOLINT注釋指示clang-tidy忽略同行中的警告(它不適用于一個函數、一個代碼塊或任何其他語言結構,它僅僅適用于所在的代碼行)。如果在同一行中引入注釋會改變格式化,那么NOLINTNEXTLINE注釋允許在下一行中壓制clang-tidy警告。
這兩個注釋都可以在后面的括號里加上一個可選的校驗名列表(見下面的正式語法)。
比如:
class?Foo?{
//?禁止該行的所有診斷程序。
Foo(int?param);?//?NOLINT
//?考慮解釋一下消除警告的動機。
Foo(char?param);?//?NOLINT:?允許從?"char?"進行隱式轉換,因為<某種有效理由>。
//?只對指定的檢查行進行消除
Foo(double?param);?//?NOLINT(google-explicit-constructor,?google-runtime-int)
//?只消除對下一行的指定診斷
//?NOLINTNEXTLINE(google-explicit-constructor,?google-runtime-int)
Foo(bool?param);
};
NOLINT/NOLINTNEXTLINE的正式語法如下:
lint-comment:
lint-command
lint-command?lint-args
lint-args:
(?check-name-list?)
check-name-list:
check-name
check-name-list?,?check-name
lint-command:
NOLINT
NOLINTNEXTLINE
注意,在NOLINT/NOLINTNEXTLINE和開頭的括號之間不允許使用空格,而在校驗名列表中(在括號內)可以使用空格,并將被忽略。
【官方網站】
https://clang.llvm.org/extra/clang-tidy
【最新版本】
Extra Clang Tools 10
【License】
Apache License 2.0
【Coccinelle】
Coccinelle(法語為瓢蟲的意思)是一個開源工具,用于匹配和轉換用C語言編寫的程序源代碼。
Coccinelle最初是用來幫助Linux內核進化的,它提供了對庫應用程序設計接口(API)的修改支持,例如重命名一個函數,添加一個值與上下文相關的函數參數,以及重組數據結構。
它還可以用來發現代碼中存在缺陷的編程模式(即高概率錯誤的代碼片段,如可能出現的NULL指針去掉指針等),而不需要對其進行改造。那么coccinelle的作用就接近于靜態分析工具的作用。這類使用的例子有herodotos工具的應用,它可以跟蹤coccinelle產生的警告。
對Coccinelle的支持是由IRILL提供的。開發資金由法國國家研究機構、丹麥技術和生產科學研究委員會和INRIA提供。
Coccinelle的源代碼是根據GNU通用公共許可證(GPL)第2版的條款授權的。
語義補丁語言
要匹配或替換的源碼使用基于補丁語法的?"語義補丁?"語法來指定,語義補丁語言(Semantic Patch Language,SmPL)模式近似于基于C語言的聲明的統一的差別。
例子
@@
expression?lock,?flags;
expression?urb;
@@
spin_lock_irqsave(lock,?flags);
<...
-?usb_submit_urb(urb)
+?usb_submit_urb(urb,?GFP_ATOMIC)
...>
spin_unlock_irqrestore(lock,?flags);
@@
expression?urb;
@@
-?usb_submit_urb(urb)
+?usb_submit_urb(urb,?GFP_KERNEL)
【官方網站】
http://coccinelle.lip6.fr/
【最新版本】
1.0.7于2018年8月31日
【License】
GPLv2
【CPAchecker】
CPAchecker是一個用于C語言程序的正式軟件驗證和程序分析的框架和工具。它的一些思想和概念,例如懶惰抽象,是繼承自軟件模型檢查器BLAST。CPAchecker是基于可配置程序分析的思想,它的概念是允許用一個規矩來表達模型檢查和程序分析。在執行時,CPAchecker會進行可達性分析,即檢查違反給定規范的某一狀態是否有可能達到。
CPAchecker的一個應用是對Linux設備驅動程序的驗證。
業內表現
CPAchecker在2012年在塔林舉行的TACAS 2012首屆軟件驗證大賽(2012年)中獲得了兩個組別(綜合類和ControlFlowInteger)的第一名。
CPAchecker在2013年在羅馬舉行的第二屆軟件驗證大賽(2013年)中獲得了第一名(綜合類)
架構
CPAchecker基于控制流自動機(CFA)進行操作;在CPA算法分析一個給定的C程序之前,它被轉化為CFA。CFA是一個定向圖,其邊代表假設或分配,節點代表程序位置。
【官方網站】
http://cpachecker.sosy-lab.org/
【最新版本】
1.9于2019年11月
【License】
Apache License 2.0
【Cppcheck】
Cppcheck是C/C++編程語言的靜態代碼分析工具。這是一個通用的工具,可以檢查非標準代碼。創建者和首席開發人員是Daniel Marjamüki。
cppcheck是GNU通用公共許可證下的免費軟件。
特點
Cppcheck支持編譯器本身可能無法覆蓋的各種靜態檢查。這些檢查是靜態分析檢查,可以在源代碼級別執行。該程序是針對靜態分析檢查是嚴格的,而不是啟發式的性質。?支持的一些檢查包括:
l??自動變量檢查
l??數組越界的界限檢查
l??類檢查(如:未使用的函數、變量初始化和內存復制)
l??Open Group中棄用或替代函數的使用
l??異常安全檢查,如內存分配使用、析構函數檢查等
l??內存泄漏,例如由于未進行解分配而丟失范圍
l??資源泄漏,如忘記關閉文件句柄
l??標準模板庫函數和習語的無效使用
l??使用unusedFunction選項消除死代碼?雜項文體和性能錯誤
和許多分析程序一樣,有許多編程習慣用法的不尋常情況,這些習慣用法在特定的目標情況下是可以接受的,或者在程序員的源代碼修正范圍之外。2009年3月進行的一項研究表明,Cppcheck在幾個領域發現了誤報,但沒有具體說明檢查的程序版本。cppcheck已被確定用于CERNs4DSOFTmeta分析程序包等系統,用于高能粒子探測器讀出裝置的代碼驗證、射電望遠鏡的系統監測軟件以及大型項目的誤差分析。例如:OpenOffice.org、Debian歸檔文件等。
開發狀態
該項目正在積極開發之中,并積極在不同發行地進行維護。它在許多流行的項目中發現了有效的錯誤,比如Linux內核和MPlayer。
插件
存在以下IDE的插件:
CLion
Code::Blocks
CodeLite
Eclipse
Emacs
gedit
Hudson
Jenkins
Kate
KDevelop
Qt Creator
Sublime Text
Yasca
【官方網站】
http://cppcheck.sourceforge.net/
【最新版本】
1.9于2019年12月
【License】
GPL
【Cpplint】
cpplint或cpplint.py是Google開發的一款開源的lint-like工具,旨在確保C++代碼符合Google的編碼風格規范。
因此,cpplint實現了Google認為的C++編碼方面的最佳實踐。腳本cpplint.py讀取源代碼文件并標記與樣式指南的偏差。它還可以識別語法錯誤。它是基于規則的,并使用許多啟發式方法來識別壞代碼。
cpplint.py存在誤報和漏報。誤報可以通過添加// NOLINT(或// NOLINT(rule))來消除,只抑制被歸罪的規則類別。
此外,可以使用--verbose和--filter選項來選擇細粒度的規則。線長規則可配置option --linelength,文件擴展名可配置--extensions(默認'h',?'cpp',?'cc',?'cu',?'cuh')。一些選項可以存儲在配置文件CPPLINT.cfg中。
Cpplint是用Python腳本實現的。
【官方網站】
https://github.com/google/styleguide/tree/gh-pages/cpplint
【最新版本】
1.4.4于2019年2月23日
【License】
BSD License 3
【Codan】
Codan是CDT中的輕量級靜態分析框架,允許輕松插入“檢查器”,對代碼進行實時分析,以發現常見缺陷、違反策略等。
Codan框架使用對象:
工具供應商
l??創建包含終端用戶檢查器和模板的插件。
l??將命令行靜態分析工具集成到CDT中,使用通用的前端工具
開發人員、測試人員、代碼檢查員
l??在開發過程中,為了在輸入時檢查是否有錯誤,并有一個快速修復錯誤的方法。
l??在代碼檢查過程中和代碼執行前,發現BUG、安全違規、違反API、違反編碼標準、違反編碼標準等問題。
軟件架構師,流程執行
l??根據模板創建自定義的新檢查器(不涉及編程)。
l??創建問題簡介
框架包含了C/C++靜態分析工具之間共享的通用組件和API,如:
l??用戶界面控制問題的啟用和參數控制
l??不同的加載模式(類型,需求,構建者)。
l??一個eclipse視圖,用于顯示額外的問題信息(如額外的回溯線或更復雜的問題參數)。
l??一種通用標記類型,適用于有額外字段的問題。
l??用來記錄問題的API
l??檢查器的基礎類
l??JUnit測試框架
l??檢查器的例子
l??代碼的控制流程圖
l??用于訪問C/C++ AST和Scanner信息的API供檢查器開發者使用(不屬于此插件,但屬于CDT核心的一部分)。
l??快速修復的例子(和一些輔助類)
l??檢查器的常用范圍過濾器
用戶體驗
【運行方式】
代碼分析可以通過以下方式之一來調用:
l??從導航上下文菜單中選擇?"運行代碼分析?"命令(文件、目錄、項目或組合)。
l??在項目首選項?"C/C++代碼分析->構建?"中啟用?"Run on Build",在這種情況下,它將以增量和完全構建的方式運行。
l??當你輸入代碼時。
l??保存文件時。
l??從命令行運行
eclipse -noSplash -application org.eclipse.cdt.codan.core.application -data
Usage:?[options]?
Options:
-all?-?run?on?all?projects?in?workspace
-verbose?-?print?verbose?build?information
使用方法:?[選項]
選項:
-all -?在工作區中的所有項目上運行
-verbose -?打印verbose構建信息。
注意:在windows系統上運行eclipsec。
如果你想將其作為自動構建的一部分運行,你還需要
a)?創建工作區并在命令行中引用
b)?將所有需要的項目導入到工作區中。
c)?確保所有項目都有索引
上面的所有操作都可以通過命令行使用另一個?cdt?應用程序?"org.eclipse.cdt.managedbuilder.core.headlessbuild",通過參數-import?或?-importAll?選項來完成
【視圖】
如果發現了問題,它們將顯示在?"問題?"視圖中。每個問題都有一個特定的類型,可以通過視圖控件進行分組或過濾。
問題詳情視圖可以顯示關于問題的額外信息,它可以自定義(通過插件)顯示任何外部鏈接或關于問題的額外信息,而這些額外信息在問題視圖中是不可用的。默認情況下,它顯示完整的文件和路徑,完整的信息和問題描述。
【定制化】
用戶可以在工作空間級別或項目級別上控制問題的嚴重性和啟用開關。
很多問題都是可以自定義的,你可以設置額外的檢查器選項和/或設置一個范圍。
Splint是Secure Programming Lint的簡稱,是一個用于靜態檢查C程序是否存在安全漏洞和編碼錯誤的編程工具。它的前身叫LCLint,是Unix lint工具的現代版本。
Splint具有對源代碼的特殊注釋進行解釋的能力,這使得它的檢查能力比單看源代碼更強。Splint被gpsd作為零缺陷設計的一部分。
Splint是在GNU通用公共許可證條款下發布的自由軟件。
Splint?的開發活動在?2010?年停止了。根據SourceForge的CVS,截止到2012年9月,版本庫中最近的變化是在2010年11月。截至2018年6月,GitHub上的git倉庫也是如此,顯示自2010年11月以來沒有任何變化。
【例子】
問題代碼
#include?
int?main()
{
char?c;
while?(c?!=?'x');
{
c?=?getchar();
if?(c?=?'x')
return?0;
switch?(c)?{
case?'\n':
case?'\r':
printf("Newline\n");
default:
printf("%c",c);
}
}
return?0;
}
Splint's?輸出
Variable?c?used?before?definition
Suspected?infinite?loop.?No?value?used?in?loop?test?(c)?is?modified?by?test?or?loop?body.
Assignment?of?int?to?char:?c?=?getchar()
Test?expression?for?if?is?assignment?expression:?c?=?'x'
Test?expression?for?if?not?boolean,?type?char:?c?=?'x'
Fall?through?case?(no?preceding?break)
定義前使用的變量c
懷疑是無限循環。循環測試中使用的值(c)沒有被測試或循環體修改。
將int指定為char:c = getchar()
If內是賦值表達式:?c = 'x'
If內不是布爾型數值,類型為char: c = 'x'
Case中沒有break
修改后的代碼
#include?
int?main()
{
int?c?=?0;??//?添加了一個初始賦值定義
while?(c?!=?'x')?{
c?=?getchar();??//?修正后的c類型為int
if?(c?==?'x')?//?修正了賦值錯誤,使其成為比較運算符。
return?0;
switch?(c)?{
case?'\n':
case?'\r':
printf("Newline\n");
break;??//?添加了break語句以防止掉線。
default:
printf("%c",c);
break;??//在默認的分支中添加了break語句。
}
}
return?0;
}
【官方網站】
https://splint.org/
【最新版本】
3.1.2于2010年8月5日
【License】
GPL
【小結】
本文對于開源項目類別的C/C++編譯器和靜態分析工具進行了探究,可以看出每種工具都有其專注的領域,在業務開發過程中,我們應該從實際出發,針對已經存在的大量歷史性代碼,如果他們的編寫風格不統一,要分階段,嘗試不同的工具來進行優化,對于遇到的問題附帶解決的方法,應該整理出來形成文檔,從而對以后的業務開發提供幫助和借鑒。
C 語言 C++
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。