亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 14478 | 回復(fù): 4
打印 上一主題 下一主題

pc_lint的用法轉(zhuǎn) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2010-08-07 10:48 |只看該作者 |倒序?yàn)g覽
如題

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2010-08-08 11:18 |只看該作者
PC-Lint是一款C/C++軟件代碼靜態(tài)分析工具,不僅可以檢查一般的語(yǔ)法錯(cuò)誤,還可以檢查潛在的錯(cuò)誤,比如數(shù)組訪問(wèn)越界、內(nèi)存泄漏、使用未初始化變量、使用空指針等。在單元測(cè)試前使用PC-Lint來(lái)檢查代碼,可以提前發(fā)現(xiàn)程序中的潛在的錯(cuò)誤,提高代碼
的質(zhì)量。
本文主要從兩個(gè)方面介紹PC-lint,第一部分是在與不同的工具安裝集成,第二部分是PC-lint的使用方法。

1. 安裝PC-lint及如何集成到VC6.0和Source Insight
1.1 安裝PC-lint
(1)下載PC-lint(PC-Lint 8.00w)。
(2)將下載的壓縮包解壓至到D盤,并對(duì)文件夾重命名為PC-Lint,這樣路徑為D:\PC-Lint。
備注:這也叫安?呵呵,似乎算免安裝更合適吧。
1.2 將PC-lint集成到VC6.0
1.2.1 對(duì)單個(gè)C/C++進(jìn)行靜態(tài)代碼分析
(1)將D:\PC-Lint\lnt 下的3個(gè)文件lib-w32.lnt,env-vc6.lnt,co-msc60.lnt復(fù)制到D:\PC-Lint\下。
(2)打開(kāi)co-msc60.lnt,將該文件倒數(shù)第二行"lib-ole.lnt"的內(nèi)容改為"D:\PC-Lint\lnt\lib-ole.lnt",也就是在前面加上絕對(duì)路徑,以免在后面的步驟中無(wú)法找到該文件。
(3)在D:\PC-Lint\下創(chuàng)建std.lnt和options.lnt兩個(gè)文件,其中std.lnt的內(nèi)容如下:

注:-i后面的路徑名為VC 6.0的安裝路徑和及其頭文件路徑;options.lnt可以暫時(shí)為空。
(4)在VC6.0的菜單欄中,Tools--->Customize...-->tools 新建一個(gè)名為pclint的項(xiàng),在下面填入
"Command"項(xiàng)填入: D:\PC-Lint\lint-nt.exe
"Argument"項(xiàng)填入: -u D:\PC-Lint\std.lnt  D:\PC-Lint\env-vc6.lnt "$(FilePath)"

然后在Use Output Window 打上勾即可。
(5)在VC6.0的菜單欄Tools下多了一個(gè)pclint選項(xiàng),打開(kāi)一個(gè)VC項(xiàng)目后,就可以使用該選項(xiàng)對(duì)單個(gè)C/C++文件進(jìn)行靜態(tài)代碼分析了。

1.2.2 對(duì)一個(gè)VC6.0項(xiàng)目進(jìn)行靜態(tài)代碼分析
下面的步驟是在1.2.1的前三步的基礎(chǔ)上進(jìn)行的。
(1)先到http://www.weihenstephan.de/~syring/win32/UnxUtils.zip下載UnxUtils.zip。需要利用unix中的find等命令來(lái)查找當(dāng)前目錄下的C和C++文件,然后再將它們送給lint程序處理。
(2)解壓UnxUtils.zip到D盤,這樣路徑為D:\UnxUtils。
(3)在在VC6.0的菜單欄Tools下多了一個(gè)pclint_prj選項(xiàng),打開(kāi)一個(gè)VC項(xiàng)目后,就可以使用該選項(xiàng)對(duì)單個(gè)C/C++文件進(jìn)行靜態(tài)代碼分析了。
"Command"項(xiàng)填入: D:\UnxUtils\usr\local\wbin\find.exe
"Argument"項(xiàng)填入: $(FileDir) -name *.c -o -name *.cpp | D:\UnxUtils\usr\local\wbin\xargs D:\PC-Lint\lint-nt -i"D:\UnxUtils\usr\local" -u D:\PC-Lint\std.lnt D:\PC-Lint\env-vc6.lnt

然后在Use Output Window 打上勾即可。
(4)在VC6.0的菜單欄Tools下多了一個(gè)pclint_prj選項(xiàng),打開(kāi)一個(gè)VC項(xiàng)目后,就可以使用該選項(xiàng)對(duì)VC項(xiàng)目進(jìn)行靜態(tài)代碼分析了。
注意:"Argument"項(xiàng)填的內(nèi)容一定要注意參數(shù)中的路徑,如果你不使用上述路徑,可以用新路徑將參數(shù)中的路徑替換,以免重新寫參數(shù)而導(dǎo)致出錯(cuò)。

1.3 將PC-lint集成到Source Insight 3.5中
1.3.1 對(duì)單個(gè)C/C++進(jìn)行靜態(tài)代碼分析
(1)打開(kāi)SourceInsight, 選擇Options-->Custom Commands-->Add, 輸入pclint
(2)在Run中填寫: D:\PC-Lint\lint-nt -u D:\PC-Lint\std.lnt D:\PC-Lint\env-vc6.lnt %f
(3)Dir不用填寫,將Iconic Window, Capture Output, Parse Links in OutPut,三項(xiàng)勾選上,并將File,then Line的單項(xiàng)選擇也選上。
(4)然后點(diǎn)右側(cè)的Menu...,在彈出的界面中在下拉框Menu中選擇View,然后在下面的Menu Cotents中選擇<end of menu>, 右側(cè)點(diǎn)Insert即可。
(5)可以在Source Insight 3.5菜單View下看到剛才新建的項(xiàng)pclint,打開(kāi)項(xiàng)目的任意一個(gè)待分析的源文件,運(yùn)行pclint即可進(jìn)行靜態(tài)代碼分析了。

1.3.2 對(duì)一個(gè)項(xiàng)目進(jìn)行靜態(tài)代碼分析
下面的步驟是在1.2.2的基礎(chǔ)上進(jìn)行的。
(1)打開(kāi)SourceInsight, 選擇Options-->Custom Commands-->Add, 輸入pclint_prj
(2)在Run中填寫:
D:\UnxUtils\usr\local\wbin\find.exe %d -name *.c -o -name *.cpp | D:\UnxUtils\usr\local\wbin\xargs D:\PC-Lint\lint-nt -i"D:\UnxUtils\usr\local" -u D:\PC-Lint\std.lnt D:\PC-Lint\env-vc6.lnt
(3)Dir不用填寫,將Iconic Window, Capture Output, Parse Links in OutPut,三項(xiàng)勾選上,并將File,then Line的單項(xiàng)選擇也選上。
(4)然后點(diǎn)右側(cè)的Menu...,在彈出的界面中在下拉框Menu中選擇View,然后在下面的Menu Cotents中選擇<end of menu>, 右側(cè)點(diǎn)Insert即可。
(5)可以在Source Insight 3.5菜單View下看到剛才新建的項(xiàng)pclint_prj,打開(kāi)項(xiàng)目,運(yùn)行pclint_prj即可對(duì)項(xiàng)目進(jìn)行靜態(tài)代碼分析了。

2.PC-lint的用法

2.1 pc-lint目錄下幾個(gè)重要的文件及程序
lint-nt.exe:PC-lint的可執(zhí)行程序。
config.exe: PC-lint的配置文件程序。
pc-lint.pdf:PC-lint的PDF格式的在線手冊(cè),本文的大部分內(nèi)容是從中得來(lái)的。
msg.txt:     對(duì)于錯(cuò)誤消息編號(hào)的詳細(xì)解釋。
Lnt\:       這個(gè)目錄下有些東西還是值得認(rèn)識(shí)一下。
co-....lnt: 指定的編譯器的可選編譯文件。
co.lnt:     通用的可選編譯文件。
sl-....c     非ANSI編譯器的標(biāo)準(zhǔn)庫(kù)文件模塊
sl.c:        非ANSI編譯器的通用標(biāo)準(zhǔn)庫(kù)文件模塊
env-....lnt:不同平臺(tái)下的可選文件,包括MS Visual Studio和其他各種編輯工具。
lib-....lnt:可選文件, 特定的"有挑戰(zhàn)性"的庫(kù)文件。
au-....lnt: 可選文件, 作者們推薦的檢測(cè)條件。

2.2 PC-lint的介紹
2.2.1 錯(cuò)誤信息編號(hào)
對(duì)于大部分的錯(cuò)誤消息,PC-lint都提供了一個(gè)關(guān)聯(lián)的錯(cuò)誤編號(hào)。小于1000的錯(cuò)誤編號(hào)是分配給C語(yǔ)言的,1000以上的錯(cuò)誤編號(hào)則是分配給C++語(yǔ)言的。1000呢?呵呵,被保留了。先看一個(gè)表格。
                                 C              C++           告警級(jí)別
語(yǔ)法錯(cuò)誤(Syntax Errors)      1   - 199      1001 - 1199           1
內(nèi)部錯(cuò)誤(Internal Errors)    200 - 299                            0
致命錯(cuò)誤(Fatal Errors)       300 - 399                            0
告警(Warnings)               400 - 699      1400 - 1699           2
提示(Informational)          700 - 899      1700 - 1899           3
可選信息(Elective Notes)     900 - 999      1900 - 1999           4

對(duì)于C語(yǔ)言,1~199是與語(yǔ)法錯(cuò)誤;200~299是PC-lint內(nèi)部錯(cuò)誤,應(yīng)該決不會(huì)發(fā)生的;300~399是致命錯(cuò)誤,通常是由于超越了某些限制;400~699是警告消息,提示被檢查的程序中可能存在錯(cuò)誤;700~899是提示信息,這些提示信息可能有錯(cuò)誤,也可能是合法的程序,取決于個(gè)人的編程風(fēng)格;900~999則是一些稱為可選信息,一般不會(huì)自動(dòng)輸出。

PC-lint提供了高級(jí)級(jí)別設(shè)置選項(xiàng)-wLevel,缺省的級(jí)別為3級(jí)。-w0, -w1 , -w2, -w3, -w4 分別可以生成上述表格中對(duì)應(yīng)告警級(jí)別和級(jí)別更低的告警,其中級(jí)別越低告警越重要。同樣,也提供了處理庫(kù)函數(shù)的頭文件告警級(jí)別的選項(xiàng)-wlib(Level),缺省的級(jí)別也是3級(jí),級(jí)別對(duì)應(yīng)的含義與前者一樣。

2.2.2 選項(xiàng)的規(guī)則
通過(guò)使用加號(hào)"+"和減號(hào)"-",以注釋的形式插入代碼中,來(lái)恢復(fù)和屏蔽指定的被檢查的選項(xiàng)。格式如下:
/*lint option1 option2 ... optional commentary */
或者
//lint option1 option2 ... optional commentary
注意:lint必須是小寫,選項(xiàng)的一行不能超過(guò)80個(gè)字符,否則導(dǎo)致致命的錯(cuò)誤,錯(cuò)誤信息的編號(hào)就是323。如果選項(xiàng)確實(shí)有很長(zhǎng),可以通過(guò)換行的方式來(lái)實(shí)現(xiàn)。另外屏蔽和恢復(fù)的選項(xiàng)的代碼可以放在宏定義中,宏被展開(kāi)后,這些選項(xiàng)會(huì)生效。

2.2.3 選項(xiàng)中的空格
因?yàn)榭崭袷怯脕?lái)分隔選項(xiàng)的,除此之外只能出現(xiàn)在圓括號(hào)的旁邊或是空格自身被引用(例如operator new按語(yǔ)法要求中間就有空格)。舉個(gè)例子:
-esym(534,printf,scanf,operator new)
-esym(534, printf, scanf, operator new)
-esym( 534 , printf , scanf , operator new )
對(duì)于第三個(gè),空格出現(xiàn)在圓括號(hào)的旁邊,也出現(xiàn)在自身被引用的地方(operator new)。另外operator和new之間出現(xiàn)兩個(gè)空格也是不合法的,因?yàn)樗`反了語(yǔ)法規(guī)則。另外,也可以使用雙引號(hào)(""來(lái)保護(hù)空格,例如:
-"dWORD=unsigned short"

2.2.4 選項(xiàng)的分類
PC-lint的選項(xiàng)有300多種,可以分為下面幾類:
(1)禁止錯(cuò)誤信息
選項(xiàng)開(kāi)頭使用"-e"可以禁止指定的錯(cuò)誤消息,使用"+e"恢復(fù)指定的錯(cuò)誤消息。如果禁止消息,只不過(guò)不讓消息輸出,并不影響PC-lint的處理過(guò)程。順便提一下前面提到的"-wLevl",這個(gè)選項(xiàng)是禁用指定級(jí)別及以上的消息的顯示。

1)格式一:
-e#  禁止指定的錯(cuò)誤消息,#代表數(shù)字或是數(shù)字匹配符,錯(cuò)誤消息的編號(hào)為#。
+e#  恢復(fù)指定的錯(cuò)誤消息,錯(cuò)誤消息的編號(hào)為#。

舉個(gè)例子:
/*lint -504*/
...Code.....
/*lint +504*/
第一行關(guān)閉了編號(hào)為504的錯(cuò)誤消息,最后一個(gè)行則重新打開(kāi)了編號(hào)為504的錯(cuò)誤消息。其中數(shù)字也可以包含匹配符號(hào),'?'匹配單個(gè)字符,"*"匹配多個(gè)字符。
比如:
(1)-e7???, 則關(guān)閉了700~799這個(gè)范圍內(nèi)的錯(cuò)誤消息。
(2)-e1*, 則關(guān)閉了所有以1開(kāi)頭的編號(hào)的錯(cuò)誤消息。
同樣匹配符也能使用在-esym, -elib, -elibsym, -efile, -efunc, -emacro, -etemplate, -e(#), --e(#), -e{#} and –e{#}.

2)格式二:
-e(#[,#]...) 為下一個(gè)表達(dá)式禁止指定的錯(cuò)誤消息,在這個(gè)表達(dá)式結(jié)束后被禁止的錯(cuò)誤消息自動(dòng)恢復(fù),#代表數(shù)字或是數(shù)字匹配符,錯(cuò)誤消息的編號(hào)為#。
舉個(gè)例子:
a = /*lint -e(413) */ *(char *)0;
它等價(jià)于下面的語(yǔ)句:
a = /*lint -save -e413 */ *(char *)0
/*lint -restore */;
前一種方法更簡(jiǎn)單且更有效。

3)格式三:
--e( # [,#]... ) 比上面的那個(gè)管的更寬一些,它對(duì)整個(gè)表達(dá)式有效,舉個(gè)例子就明白它與上面的區(qū)別了。
舉個(gè)例子:
a = /*lint --e(413) */ *(int *)0 + *(char *)0;
整個(gè)表示式是指*(int *)0 + *(char *)0,下個(gè)一表達(dá)式指的是*(int *)0。區(qū)別一目了然,例子中將禁止兩個(gè)編號(hào)為413 的錯(cuò)誤消息, 如果使用 -e(413) ,則只禁止第一個(gè)編號(hào)為 413 的錯(cuò)誤消息。

4)格式四:
-e{ # [, #] …} 對(duì)下一個(gè)語(yǔ)句或者聲明有效
舉個(gè)例子:
//lint -e{715} suppress "k not referenced"
void f( int n, unsigned u, int k )
{
    //lint -e{732} suppress "loss of sign"
    u = n; // 732 not issued
    //lint -e{713} suppress "loss of precision"
    if(n)
   {
       n = u; // 713 not issued
   }
} // 715 not issued
通過(guò)例子可以看出,這種格式放在函數(shù)之前,則對(duì)整個(gè)函數(shù)產(chǎn)生作用,放在賦值語(yǔ)句前則只對(duì)賦值語(yǔ)句起作用,放在if或while前面,則對(duì)這一段語(yǔ)句起作用。在C++的類定義或命名空間聲明前放這么個(gè)選項(xiàng),則將整個(gè)類或命名空間內(nèi)的代碼中指定的錯(cuò)誤消息給禁止了。

5)格式五:
--e{ # [, #] … } 對(duì)于其所處的 {} 號(hào)區(qū)域內(nèi)的整個(gè)代碼體有效。 {} 號(hào)區(qū)域可能是復(fù)雜的語(yǔ)句、函數(shù)體、C++的類,結(jié)構(gòu)體或聯(lián)合體的定義、C++的命名空間等。如果這個(gè)選項(xiàng)放在一個(gè)模塊前,而模塊前沒(méi)有 {},則對(duì)整個(gè)模塊生效。

6)格式六:
!e# 僅對(duì)其所在行有效。
if( x = f(34) ) //lint !e720
y = y / x;
在這個(gè)例子中,僅對(duì)那一行禁止編號(hào)為720 的錯(cuò)誤消息?匆幌翪語(yǔ)言的代碼的用法:
if( x = f(34) ) /*lint !e720 */
y = y / x;
如果有更多的錯(cuò)誤信息要禁止,而又無(wú)法使用通配符,則可以使用下面的方法:
n = u / -1; //lint !e573 !e721

7)格式七:
-ealetter 參數(shù)不匹配禁止

格式八:
-efile( #, file [, file] ... ) inhibits and
+efile( #, file [, file] ... ) re-enables

9)格式九:
-efunc( #, Symbol [, Symbol] ... ) inhibits and
+efunc( #, Symbol [, Symbol] ... ) re-enables

10)格式十:
-elib( # [, #] ... ) inhibits and
+elib( # [, #] ... ) re-enables

11)格式十一:
-elibsym( # [, # ] ... ) inhibits
+elibsym( # [, # ] ... ) re-enables

12)格式十二:
-emacro( #, symbol, ... )
+emacro( #, symbol, ... )

13)格式十三:
-emacro( (#), symbol, ... )
--emacro( (#), symbol, ... )
-emacro( {#}, symbol, … )
--emacro( {#}, symbol, … )

14)格式十四:
-esym( #, Symbol [, Symbol] ... ) inhibits and
+esym( #, Symbol [, Symbol] ... ) re-enables
禁止和恢復(fù)指定的符號(hào)的錯(cuò)誤消息。舉個(gè)C++的例子(實(shí)際應(yīng)用中不太可能出現(xiàn)):
class X
{
    void f(double, int);
};
分析結(jié)果中會(huì)提示某行的member X::f(double, int)沒(méi)有被引用,為了屏蔽這個(gè)消息,你可以使用
-esym( 754, X::f )
符號(hào)的完整簽名為X::f(double, int),然而符號(hào)的名字為X::f,而且可以使用符號(hào)的名字來(lái)禁止錯(cuò)誤消息的出現(xiàn)。另外,-esym 和 -e# 選項(xiàng)是獨(dú)立的,舉個(gè)例子:
-e714 +esym( 714,alpha )
對(duì)于alpha來(lái)說(shuō),它禁止了編號(hào)為714的錯(cuò)誤消息,第二個(gè)選項(xiàng)并不會(huì)恢復(fù)編號(hào)為714的錯(cuò)誤消息,除非前面有個(gè)對(duì)應(yīng)的-esym(714,alpha)。

15)格式十五:
-etd( TypeDiff [, ...] ) inhibits
+etd( TypeDiff [, ...] ) re-enables

16)格式十六:
-etemplate( # [,#] ... )
+etemplate( # [,#] ... )
禁止和恢復(fù)在擴(kuò)展模板(expanding templates)時(shí)的錯(cuò)誤消息。

(2)變量類型大小和對(duì)齊選項(xiàng)
1)變量類型大小選項(xiàng)
這組選項(xiàng)允許設(shè)置各種變量類型的大小和對(duì)齊方式。由于默認(rèn)的設(shè)置于絕大多數(shù)的編譯器都是一致的,所以這些參數(shù)的單獨(dú)設(shè)置通常是沒(méi)有必要的。使用變量類型大小的選項(xiàng)是為了特定的架構(gòu),而不是本地架構(gòu)。舉個(gè)例子,你需要為嵌入式系統(tǒng)設(shè)置int和pointers通常為16位,那么你應(yīng)該指定:
lint -si2 -sp2 ...
下面的列表,#號(hào)代表一個(gè)小的整型值,僅舉幾個(gè):
-sb# 字節(jié)的位數(shù)為#,默認(rèn)的是-sb8,
-sbo# sizeof(bool)就變?yōu)橐粋(gè)參數(shù)了,默認(rèn)值為1,
-sc# sizeof(char) 就變?yōu)?#,默認(rèn)值為1,
-slc# sizeof(long char) 就變?yōu)?#,默認(rèn)值為2,
...
2)對(duì)齊選項(xiàng)
僅有兩個(gè)可選擇的注釋信息來(lái)檢測(cè)不規(guī)律的對(duì)齊,它們的錯(cuò)誤編號(hào)是958和959,詳細(xì)的介紹就省略了吧。

(3)冗長(zhǎng)信息選項(xiàng)
冗長(zhǎng)信息選項(xiàng)采用-v和+v開(kāi)頭來(lái)控制,冗長(zhǎng)信息指的是在檢測(cè)過(guò)程中產(chǎn)生的一些與編譯過(guò)程有關(guān)的信息,或者說(shuō),冗長(zhǎng)信息與編譯過(guò)程中消息的頻率和種類有關(guān)。如果使用-v,則冗長(zhǎng)信息進(jìn)被發(fā)送到標(biāo)準(zhǔn)輸出,而是用+v,冗長(zhǎng)信息進(jìn)則會(huì)被發(fā)送到標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤中。如果要將錯(cuò)誤信息重定向到一個(gè)文件中,并想要在終端查看冗長(zhǎng)信息和被解釋后的錯(cuò)誤消息,+v選項(xiàng)是非常有用的。

(4) 標(biāo)志選項(xiàng)
采用+f,++f,-f,--f開(kāi)頭開(kāi)介紹標(biāo)志位。一個(gè)標(biāo)志位在內(nèi)部采用一個(gè)整型值表達(dá)。通過(guò)認(rèn)為:
ON  假如整型值大于0
OFF 假如整型值小于或等于0
默認(rèn)設(shè)置時(shí)1為ON,0為off,對(duì)于的關(guān)系如下:
+f...:通過(guò)把標(biāo)志為設(shè)置為1而把它設(shè)置為ON
-f...:通過(guò)把標(biāo)志為設(shè)置為0而把它設(shè)置為OFF
++f...:標(biāo)志位增1
--f...:標(biāo)志位減1
后面兩個(gè)選項(xiàng)在只設(shè)置局部標(biāo)志而不影響全局設(shè)置時(shí),非常有用。

(5)消息顯示選項(xiàng)
消息顯示選項(xiàng)用于定義消息輸出的格式。
1)控制錯(cuò)誤消息的高度。
-h選項(xiàng)被用來(lái)控制消息的高度,通常的格式如下:
-h[F][f][a][r][mn][m][m/M/][I]N
s 表示每條消息后的空格。其他的就不介紹了。
2)控制錯(cuò)誤消息的寬度。
格式如下:
-width(W,Indent)
例如:-width(99,4)
3)消息格式化選項(xiàng)
格式如下
-format=...
3)附加信息選項(xiàng)
格式如下:
-append(errno,string)
(6)其他選項(xiàng)
1)-A 要求嚴(yán)格使用ANSI C/C++處理。
其他的不介紹了。

2.2.5 庫(kù)文件檢查
這里的庫(kù)文件時(shí)指那些編譯后的庫(kù)文件,比如標(biāo)準(zhǔn)的I/O庫(kù),又比如第三方的庫(kù)文件,例如windows的庫(kù)文件。關(guān)注庫(kù)文件的重要特色是因?yàn)橐韵聝牲c(diǎn):
(1)庫(kù)文件的源代碼通常不可獲得。
(2)庫(kù)文件在多個(gè)正被你使用pc-lint檢查的程序中使用。
庫(kù)的頭文件描述了庫(kù)的部分或完整的接口。舉個(gè)例子:
hello.c
#include <stdio.h>
main()
{
    HelloWorld();
    printf( "hello world\n" );
}

如果沒(méi)有"#include <stdio.h>"這一行代碼,使用PC-lint檢查上述代碼,PC-lint會(huì)抱怨printf()既沒(méi)有聲明也沒(méi)有定義,會(huì)給出編號(hào)為718錯(cuò)誤信息。如果"stdio.h"被當(dāng)做一個(gè)庫(kù)文件的頭文件,那么PC-lint不會(huì)要求給出printf()的源代碼。

(1)格式一:
+libclass( identifier[, identifier] ... )
用來(lái)指定名為identifier的頭文件當(dāng)做庫(kù)頭文件。identifier是其中下面之一:
angle: 所有尖括號(hào)包含起來(lái)的頭文件
foreign:所有在搜索列表中目錄下的頭文件
ansi:標(biāo)準(zhǔn)ANSI C/C++ 的頭文件
all:所有頭文件
默認(rèn)情況下,+libclass(angle,foreign) 是有效的,這也是為什么hello.c的代碼沒(méi)有要求給出printf()源代碼的原因。
(2)格式二:
+libdir( directory [, directory] ... )
-libdir( directory [, directory] ... )
指定目錄的。
(3)格式三:
+libh( file [, file] ... )
-libh( file [, file] ... )
增加或移出那些已經(jīng)被 +libclass 和 +/-libdir 已確定的頭文件,以達(dá)到要求或不要求給出源代碼。舉個(gè)例子:
+libclass( ansi, angle )
+libh( windows.h, graphics.h )
+libh( os.h ) -libh( float.h )
要求所有的ansi和angle(除了float.h),還有那三個(gè)windows.h, graphics.h, os.h也會(huì)被當(dāng)做庫(kù)頭文件。

2.2.6 強(qiáng)類型檢查
什么是強(qiáng)類型?C/C++的變量都有類型,不同類型之間的賦值可能會(huì)產(chǎn)生告警,可以說(shuō)C/C++變量的類型是強(qiáng)類型。有強(qiáng)類型,自然有弱類型。比如一些腳本語(yǔ)言,它們的變量就不存在具體的類型,可以相互之間賦值,它們就是弱類型語(yǔ)言。為什么在使用PC-lint對(duì)C/C++進(jìn)行檢查時(shí),要進(jìn)行強(qiáng)類型檢查呢?因?yàn)橛兄T如使用typedef定義的數(shù)據(jù)類型,可以避開(kāi)編譯器的類型檢查。舉個(gè)例子:
typedef int Count;
typedef int Bool;
Count n;
Bool stop;
...
n = stop ;

對(duì)于這段代碼,編譯器是不會(huì)告警的,但是最后一行代碼是錯(cuò)誤的。所以,強(qiáng)類型檢查選項(xiàng)是必要的。
   強(qiáng)類型檢查選項(xiàng)"-strong"和附加選項(xiàng)"-index"可以完全的或部分的對(duì)typedef定義的數(shù)據(jù)類型進(jìn)行強(qiáng)類型檢查,保證相同類型的變量才能相互賦值。
(1)強(qiáng)類型檢查選項(xiàng)strong的格式如下:
-strong( flags[, name] ... )
name是強(qiáng)類型,flags是指定的屬性,flags參數(shù)可以是A、J、X、B、b、l和f。如果name被省略,所有使用typedef定義的數(shù)據(jù)類型的flags的屬性不能被其他的-strong選項(xiàng)所識(shí)別。

flags參數(shù)  弱化字符
   A       i 忽略初始化
           r 忽略Return語(yǔ)句
           p 忽略參數(shù)傳遞
           a 忽略賦值操作
           c 忽略將常量賦值(包括整數(shù)常量、常量字符串等)給強(qiáng)類型的情況
           z 忽略Zero賦值

   X       當(dāng)把強(qiáng)類型的變量賦值給其他變量的時(shí)候進(jìn)行類型檢查。弱化參數(shù)i, r, p, a, c, z同樣適用于X并起相同的作用。
   J       當(dāng)強(qiáng)類型與其它類型進(jìn)行運(yùn)算時(shí)(邏輯運(yùn)算、關(guān)系運(yùn)算、數(shù)學(xué)運(yùn)算等)進(jìn)行檢查
           e 忽略==、!=和?:操作符
           r 忽略>、>=、<和<=
           o 忽略+、-、*、/、%、|、&和^
           c 忽略該強(qiáng)類型與常量進(jìn)行以上操作時(shí)的檢查
           z 忽略該強(qiáng)類型與Zero進(jìn)行以上操作時(shí)的檢查
   B       類型是Boolean,一般情況下只能使用一個(gè)name(指格式中的name), 而且它應(yīng)該和其他flags聯(lián)合使用。
           B選項(xiàng)有兩個(gè)作用:
           1. 出于強(qiáng)類型檢查的目的,每一個(gè)Boolean操作符都采用返回一個(gè)和Type兼容的類型。Boolean操作符就是那些顯示
              為true或false,也包括前面提到的四種關(guān)系運(yùn)算符和兩種等于判斷符,取反操作符!,二元操作符&&和||。
           2. 在所有需要判斷Bolean值的上下文中,比如if語(yǔ)句和while語(yǔ)句,都應(yīng)該檢查這個(gè)強(qiáng)類型,否則產(chǎn)生告警。
   b      僅僅假定每一個(gè)Bolean類操作符都將返回一個(gè)與Type類型兼容的返回值。與B選項(xiàng)相比,b選項(xiàng)的限制比較寬松。
   l      庫(kù)標(biāo)志,當(dāng)強(qiáng)類型的對(duì)象從庫(kù)函數(shù)中獲得值,或者將強(qiáng)類型對(duì)象的值作為參數(shù)傳遞給庫(kù)函數(shù)等情況下,不產(chǎn)生告警。
   f      與B或b連用,表示不應(yīng)該將1位長(zhǎng)度的位域當(dāng)做Boolean類型,否則表示1位長(zhǎng)度的位域被缺省假定為Boolean類型。

   這些選項(xiàng)順序?qū)δ軟](méi)有影響,但是A和J選項(xiàng)的弱化字符必須緊跟在它們之后。B選項(xiàng)和b選項(xiàng)不能同時(shí)使用,f選項(xiàng)必須搭配B選項(xiàng)或b選項(xiàng)使用,如果不指定這些選項(xiàng),-strong的作用就是僅僅聲明type為強(qiáng)類型而不作任何檢查。下面用一段代碼演示-strong選項(xiàng)的用法:
//lint -strong(Ab,Bool) <選項(xiàng)是以注釋的形式插入代碼中>
typedef int Bool;
Bool gt(int a, b)
{
    if(a) return a > b; // OK
    else return 0; // Warning
}
代碼中,Bool被聲明成強(qiáng)類型,如果沒(méi)有指定b選項(xiàng),第一個(gè)return語(yǔ)句中的比較操作就會(huì)被認(rèn)為與函數(shù)類型不匹配。第二個(gè)return語(yǔ)句導(dǎo)致告警是因?yàn)?不是Bool類型,如果添加c選項(xiàng),例如-strong(Acb,Bool),這個(gè)告警就會(huì)被禁止。
(2) 另一個(gè)強(qiáng)類型檢查選項(xiàng)是index,格式如下:
-index( flags, ixtype, sitype [, sitype] ... )
這個(gè)選項(xiàng)是對(duì)strong選項(xiàng)的補(bǔ)充,它可以和-strong選項(xiàng)一起使用。這個(gè)選項(xiàng)指定ixtype是一個(gè)排他的索引類型,它可以和強(qiáng)索引類型sitype的數(shù)組(或指針)一起使用,ixtype和sitype被假定為后來(lái)使用typedef聲明來(lái)定義的的類型名稱。flags可以是c或d,c允許將ixtype和常量作為索引使用,而d允許在不使用ixtype的情況下指定數(shù)組的維數(shù)(Dimensions)。


本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/scucj/archive/2009/08/06/4409735.aspx

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2010-08-08 11:25 |只看該作者
PC-Lint的檢查分很多種類,有強(qiáng)類型檢查、變量值跟蹤、語(yǔ)義信息、賦值順序檢查、弱定義檢查、格式檢查、縮進(jìn)檢查、const變量檢查和volatile變量檢查等等。對(duì)每一種檢查類型,PC-Lint都有很多詳細(xì)的選項(xiàng),用以控制PC-Lint的檢查效果。PC-Lint的選項(xiàng)有300多種,這些選項(xiàng)可以放在注釋中(以注釋的形式插入代碼中),例如:
/*lint option1 option2 ... optional commentary */     選項(xiàng)可以有多行
//lint option1 option2 ... optional commentary        選項(xiàng)僅為一行(適用于C++)
選項(xiàng)間要以空格分開(kāi),lint命令一定要小寫,并且緊跟在/*或//后面,不能有空格。如果選項(xiàng)由類似于操作符和操作數(shù)的部分組成,例如-esym(534, printf, scanf, operator new),其中最后一個(gè)選項(xiàng)是operator new,那么在operator和new中間只能有一個(gè)空格。PC-Lint的選項(xiàng)還可以放在宏定義中,當(dāng)宏被展開(kāi)時(shí)選項(xiàng)才生效。例如:
#define DIVZERO(x) /*lint -save -e54 */ ((x) /0) /*lint -restore */ 允許除數(shù)為0而不告警
    下面將分別介紹PC-Lint常用的,也是比較重要的代碼檢查類型,并舉例介紹了各個(gè)檢查類型下可能出現(xiàn)的告警信息以及常用選項(xiàng)的用法:

3.1 強(qiáng)類型檢查

    強(qiáng)類型檢查選項(xiàng)“-strong”和它的輔助(補(bǔ)充)選項(xiàng)“-index”可以對(duì)typedef定義的數(shù)據(jù)類型進(jìn)行強(qiáng)類型檢查,以保證只有相同類型之間的變量才能互相賦值,強(qiáng)類型檢查選項(xiàng)strong的用法是:
-strong( flags[, name] ... )
strong選項(xiàng)必須在typedef定義類型之前打開(kāi),否則PC-Lint就不能識(shí)別typedef定義的數(shù)據(jù)類型,類型檢查就會(huì)失效。flags參數(shù)可以是A、J、X、B、b、l和f,相應(yīng)的解釋和弱化字符在表 2 中列出:
表 2 強(qiáng)類型檢查strong選項(xiàng)和參數(shù)表 A                對(duì)強(qiáng)類型變量賦值時(shí)進(jìn)行類型檢查,這些賦值語(yǔ)句包括:直接賦值、返回值、參數(shù)傳遞、初始化 。
A參數(shù)后面可以跟以下字符,用來(lái)弱化A的檢查強(qiáng)度:
i   忽略初始化
r   忽略Return語(yǔ)句
p   忽略參數(shù)傳遞
a   忽略賦值操作
c   忽略將常量賦值(包括整數(shù)常量、常量字符串等)給強(qiáng)類型的情況
z   忽略Zero賦值,Zero定義為任何非強(qiáng)制轉(zhuǎn)換為強(qiáng)類型的0常量。例如:0L和(int)0都是Zero,
    但是(HANDLE)0當(dāng)HANDLE是一個(gè)強(qiáng)類型的時(shí)候就不是Zero。(HANDLE *)0也不是例如使用-strong(Ai,BITS)設(shè)置,PC-Lint將會(huì)對(duì)從非BITS類型數(shù)據(jù)向BITS類型數(shù)據(jù)賦值的代碼發(fā)出告警,但是忽略變量初始化時(shí)的此類賦值。
X 當(dāng)把強(qiáng)類型的變量賦指給其他變量的時(shí)候進(jìn)行類型檢查。弱化參數(shù)i, r, p, a, c, z同樣適用于X并起相同的作用。
J 選項(xiàng)是當(dāng)強(qiáng)類型與其它類型進(jìn)行如下的二進(jìn)制操作時(shí)進(jìn)行檢查,下面是J的參數(shù):
e   忽略==、!=和?:操作符
r   忽略>、>=、<和<=
o   忽略+、-、*、/、%、|、&和^
c   忽略該強(qiáng)類型與常量進(jìn)行以上操作時(shí)的檢查
z   忽略該強(qiáng)類型與Zero進(jìn)行以上操作時(shí)的檢查

使用忽略意味著不會(huì)產(chǎn)生告警信息。舉個(gè)例子,如果Meters是個(gè)強(qiáng)類型,那么它只在判斷相等和其他關(guān)系操作時(shí)才會(huì)被正確地檢查,其它情況則不檢查,在這個(gè)例子中使用J選項(xiàng)是正確的。

B B選項(xiàng)有兩個(gè)效果:
      1. 出于強(qiáng)類型檢查的目的,假設(shè)所有的Boolean操作返回一個(gè)和Type兼容的類型,所謂Boolean操作就是那些指示結(jié)果為true或false的操作,包括前面提到的四種關(guān)系運(yùn)算符和兩種等于判斷符,取反操作符!,二元操作符&&和||。
      2. 在所有需要判斷Bolean值的地方,如if語(yǔ)句和while語(yǔ)句,都要檢查結(jié)果是否符合這個(gè)強(qiáng)類型,否則告警。
      例如if(a)...當(dāng)a為int時(shí),將產(chǎn)生告警,因?yàn)閕nt與Bolean類不兼容,所以必須改為if(a != 0)。
b 僅僅假定每一個(gè)Bolean類操作符都將返回一個(gè)與Type類型兼容的返回值。與B選項(xiàng)相比,b選項(xiàng)的限制比較寬松。
l 庫(kù)標(biāo)志,當(dāng)強(qiáng)類型的值作為參數(shù)傳遞給庫(kù)函數(shù)等情況下,不產(chǎn)生告警。
f 與B或b連用,表示抑止對(duì)1bit長(zhǎng)度的位域是Boolean類型的假定,如果不選該項(xiàng)表示1bit長(zhǎng)度的位域被缺省假定為Boolean類型。

























    這些選項(xiàng)字符的順序?qū)δ軟](méi)有影響。但是A和J選項(xiàng)的弱化字符必須緊跟在它們之后。B選項(xiàng)和b選項(xiàng)不能同時(shí)使用,f選項(xiàng)必須搭配B選項(xiàng)或b選項(xiàng)使用,如果不指定這些選項(xiàng),-strong的作用就是僅僅聲明type為強(qiáng)類型而不作任何檢查。下面用一段代碼演示-strong選項(xiàng)的用法:

//lint -strong(Ab,Bool) <選項(xiàng)是以注釋的形式插入代碼中>
typedef int Bool;
Bool gt(int a, b)
{
if(a) return a > b; // OK
else return 0; // Warning
}
例子代碼中Bool被聲明成強(qiáng)類型,如果沒(méi)有指定b選項(xiàng),第一個(gè)return語(yǔ)句中的比較操作就會(huì)被認(rèn)為與函數(shù)類型不匹配。第二個(gè)return語(yǔ)句導(dǎo)致告警是因?yàn)?不是各Bool類型,如果添加c選項(xiàng),例如-strong(Acb,Bool),這個(gè)告警就會(huì)被抑制。再看一個(gè)例子:
/*lint -strong( AJXl, STRING ) */
typedef char *STRING;
STRING s;
...
s = malloc(20);
strcpy( s, "abc" );

由于malloc和strcpy是庫(kù)函數(shù),將malloc的返回值賦給強(qiáng)類型變量s或?qū)?qiáng)類型變量s傳遞給strcpy時(shí)會(huì)產(chǎn)生強(qiáng)類型沖突,不過(guò)l選項(xiàng)抑制了這個(gè)告警。
    強(qiáng)類型也可用于位域,出于強(qiáng)類型檢查的目的,先假定位域中最長(zhǎng)的一個(gè)字段是優(yōu)勢(shì)Boolean類型,如果沒(méi)有優(yōu)勢(shì)Boolean或位域中沒(méi)有哪個(gè)字段比其它字段長(zhǎng),這個(gè)類型從位域被切開(kāi)的位置開(kāi)始成為“散”類型,例如:
//lint -strong( AJXb, Bool )
//lint -strong( AJX, BitField )
typedef int Bool;
typedef unsigned BitField;
struct foo
{
unsigned a:1, b:2;
BitField c:1, d:2, e:3;
} x;
void f()
{
x.a = (Bool) 1; // OK
x.b = (Bool) 0; // strong type violation
x.a = 0; // strong type violation
x.b = 2; // OK
x.c = x.a; // OK
118
x.e = 1; // strong type violation
x.e = x.d; // OK
}


上面例子中,成員a和c是強(qiáng)類型Bool,成員d和e是BitField類型,b不是強(qiáng)類型。為了避免將只有一位的位域假設(shè)成Boolean類型,需要在聲明Boolean的-strong中使用f選項(xiàng),上面的例子就應(yīng)該改成這樣:-strong(AJXbf,Bool)。

    另一個(gè)強(qiáng)類型檢查選項(xiàng)是index,index的用法是:
-index( flags, ixtype, sitype [, sitype] ... )
這個(gè)選項(xiàng)是對(duì)strong選項(xiàng)的補(bǔ)充,它可以和strong選項(xiàng)一起使用。這個(gè)選項(xiàng)指定ixtype是一個(gè)排除索引類型,它可以和Strongly Indexed類型sitype的數(shù)組(或指針)一起使用,ixtype和sitype被假設(shè)是使用typedef聲明的類型名稱。flags可以是c或d,c允許將ixtype和常量作為索引使用,而d允許在不使用ixtype的情況下指定數(shù)組的長(zhǎng)度(Dimensions)。下面是一個(gè)使用index的例子:
//lint -strong( AzJX, Count, Temperature )
//lint -index( d, Count, Temperature )
// Only Count can index a Temperature
typedef float Temperature;
typedef int Count;
Temperature t[100]; // OK because of d flag
Temperature *pt = t; // pointers are also checked
// ... within a function
Count i;
t[0] = t[1]; // Warnings, no c flag
for( i = 0; i < 100; i++ )
t[i] = 0.0; // OK, i is a Count
119
pt[1] = 2.0; // Warning
i = pt - t; // OK, pt-t is a Count

上面的例子中,Temperature是被強(qiáng)索引類型,Count是強(qiáng)索引類型。如果沒(méi)有使用d選項(xiàng),數(shù)組的長(zhǎng)度將被映射成固有的類型:
Temperature t[ (Count) 100 ];
但是,這是個(gè)小麻煩,像下面那樣將數(shù)組長(zhǎng)度定義成常量更好一些:
#define MAX_T (Count) 100
Temperature t[MAX_T];

這樣做還有一個(gè)好處就是同樣的MAX_T還可以用在for語(yǔ)句中,用于限制for語(yǔ)句的范圍。需要注意的是,指向強(qiáng)被索引類型的指針(例如上面的pt)如果用在[]符號(hào)(數(shù)組符號(hào))中也會(huì)被檢查類型。其實(shí),無(wú)論何時(shí),只要將一個(gè)值加到一個(gè)指向強(qiáng)被索引類型的指針時(shí),這個(gè)值就會(huì)被檢查以確認(rèn)它是一個(gè)強(qiáng)索引類型。此外,強(qiáng)被索引指針如果減去一個(gè)值,其結(jié)果被認(rèn)為是平常的強(qiáng)索引,所以下面的例子就不會(huì)產(chǎn)生告警:
i = pt - t;

3.2 變量值跟蹤

3.2.1 變量值初始化跟蹤

    早期的變量值跟蹤技術(shù)主要是對(duì)變量值的初始化進(jìn)行跟蹤,和變量初始化相關(guān)的LINT消息主要是644, 645 ("變量可能沒(méi)有初始化"), 771, 772 ("不可靠的初始化"), 530 ("未初始化的"), and 1401 - 1403 ("成員 ... 未初始化")。以下面的代碼為例:
if( a ) b = 6;
else c = b;    // 530 message
a = c;        // 645 message

假設(shè)b和c在之前都沒(méi)有初始化,PC-Lint就會(huì)報(bào)告b沒(méi)有初始化(在給c賦值的時(shí)候)和c可能沒(méi)有被初始化(在給a賦值的時(shí)候)的消息。而while和for循環(huán)語(yǔ)句和上面的if語(yǔ)句稍微有所不同,比較下面的代碼:
while ( n-- )
{
b = 6;
...
}
c = b; //772 message

假設(shè)b在使用之前沒(méi)有被初始化,這里會(huì)報(bào)告b可能沒(méi)有初始化的消息(當(dāng)給c賦值時(shí))。之所以會(huì)有這樣的區(qū)別,是因?yàn)槌绦蛟O(shè)計(jì)者可能知道這樣的循環(huán)體總是會(huì)被至少執(zhí)行一次。相反,前面的if語(yǔ)句,對(duì)于程序設(shè)計(jì)者來(lái)說(shuō)比較難以確定if語(yǔ)句是否總會(huì)被執(zhí)行,因?yàn)槿绻沁@樣的話,這樣的if語(yǔ)句就是多余的,應(yīng)該被去掉。While語(yǔ)句和if比較相似,看下面的例子:
switch ( k )
{
case 1: b = 2; break;
case 2: b = 3;
/* Fall Through */
case 3: a = 4; break;
default: error();
}
c = b;   //645 message

盡管b在兩個(gè)不同的地方被賦值,但是仍然存在b沒(méi)有被初始化的可能。因此,當(dāng)b賦值給c的時(shí)候,就會(huì)產(chǎn)生可能沒(méi)有初始化的消息。為了解決這個(gè)問(wèn)題,你可以在switch語(yǔ)句之前給b賦一個(gè)默認(rèn)值。這樣PC-Lint就不會(huì)產(chǎn)生告警消息,但是我們也失去了讓PC-Lint檢查后續(xù)的代碼修改引起的變量初始化問(wèn)題的機(jī)會(huì)。更好的方法是修改沒(méi)有給b賦值的case語(yǔ)句。
    如果error()語(yǔ)句代表那些“不可能發(fā)生”的事情發(fā)生了,那么我們可以讓PC-Lint知道這一段其實(shí)是不可能執(zhí)行的,下面的代碼表明了這一點(diǎn):
switch ( k )
{
case 1: b = 2; break;
case 2:
case 3: b = 3; a = 4; break;
default: error();
/*lint -unreachable */
}
c = b;
注意:這里的-unreachable應(yīng)該放在error()后面,break的前面。另外一個(gè)產(chǎn)生”沒(méi)有初始化”告警的方式是傳遞一個(gè)指針給free(或者采用相似的方法)。比如:
if( n ) free( p );
...
p->value = 3;
在訪問(wèn)p的時(shí)候會(huì)產(chǎn)生p可能沒(méi)有被初始化的消息。對(duì)于goto語(yǔ)句,前向的goto可能產(chǎn)生沒(méi)有初始化消息,而向后的goto 會(huì)被忽略掉這種檢查。
if ( a ) goto label;
b = 0;
label: c = b;
當(dāng)在一個(gè)大的項(xiàng)目中使用未初始化變量檢查時(shí),可能會(huì)產(chǎn)生一些錯(cuò)誤的報(bào)告。這種報(bào)告的產(chǎn)生,很大一部分來(lái)自于不好的程序設(shè)計(jì)風(fēng)格,或者包括下面的結(jié)構(gòu):
if( x ) initialize y
...
if( x ) use y
當(dāng)出現(xiàn)這種情況時(shí),可以采用給y賦初始值的方式,或者利用選項(xiàng)-esym(644,y)關(guān)掉變量y上面的初始化檢查。

3.2.2 變量值跟蹤

    變量值跟蹤技術(shù)從賦值語(yǔ)句、初始化和條件語(yǔ)句中收集信息,而函數(shù)的參數(shù)被默認(rèn)為在正確的范圍內(nèi),只有在從函數(shù)中可以收集到的信息與此不符的情況下才產(chǎn)生告警。與變量值跟蹤相關(guān)的消息有:
(1) 訪問(wèn)地址越界消息(消息415,661,796)
(2) 被0除消息(54,414,795)
(3) NULL指針的錯(cuò)誤使用(413,613,794)
(4) 非法指針的創(chuàng)建錯(cuò)誤(416,662,797)
(5) 冗余的布爾值測(cè)試(774)

    看下面的例子:
int a[10];
int f()
{
int k;
k = 10;
return a[k]; // Warning 415
}
這個(gè)語(yǔ)句會(huì)產(chǎn)生警告415(通過(guò) '[' 訪問(wèn)越界的指針),因?yàn)镻C-Lint保存了賦給k的值,然后在使用k的時(shí)候進(jìn)行了判斷。如果我們把上面的例子稍加修改:
int a[10];
int f( int n )
{
int k;
if ( n ) k = 10;
else k = 0;
return a[k]; // Warning 661
}
這樣就會(huì)產(chǎn)生告警 661 (可能訪問(wèn)越界指針)。 使用“可能”是因?yàn)椴皇撬械穆窂蕉紩?huì)把10賦值給k。PC-Lint不僅收集賦值語(yǔ)句和初始化,還從條件語(yǔ)句中收集值的信息。比如下面的例子:
int a[10];
int f( int k, int n )
{
if ( k >= 10 ) a[0] = n;
return a[k]; // Warning 661 -- k could be 10
}
這里仍然產(chǎn)生661告警,因?yàn)镻C-Lint檢測(cè)到,在使用k的時(shí)候,k的值>=10。另外,對(duì)于函數(shù)來(lái)說(shuō),它總是假設(shè)K是正確的,程序使用者知道他們要做些什么,所以下面的語(yǔ)句不會(huì)產(chǎn)生告警:
int a[10];
int f( int k, int n )
{ return a[k+n]; } // no warning
和檢查變量沒(méi)有初始化一樣,還可以檢查變量的值是否正確。比如,如果下面例子中的循環(huán)一次都沒(méi)有運(yùn)行,k可能會(huì)超出范圍。這時(shí)候會(huì)產(chǎn)生消息796 (可預(yù)見(jiàn)的地址訪問(wèn)越界).
int a[10];
int f(int n, int k)
{
int m = 2;
if( k >= 10 ) m++; // Hmm -- So k could be 10, eh?
while( n-- )
{ m++; k = 0; }
return a[k]; // Info 796 - - k could still be 10
}
下面的例子演示了可能使用NULL指針的問(wèn)題:
int *f( int *p )
{
if ( p ) printf( "\n" ); // So -- p could be NULL
printf( "%d", *p ); // Warning
return p + 2; // Warning
}
這里會(huì)產(chǎn)生兩個(gè)告警,因?yàn)榭赡苁褂昧薔ULL指針,很明顯,這兩個(gè)語(yǔ)句應(yīng)該在if語(yǔ)句的范圍內(nèi)。為了使你的程序更加健壯,你可能需要打開(kāi)Pointer-parameter-may-be-NULL這個(gè)開(kāi)關(guān)(+fpn)。這個(gè)選項(xiàng)假設(shè)所有傳遞到函數(shù)中的指針都有可能是NULL的。數(shù)組邊界值在高位被檢測(cè),也就是說(shuō)
int a[10]; ... a[10] = 0;
被檢測(cè)了,而a[-1]卻檢測(cè)不到。PC-Lint中有兩個(gè)消息是和指針的越界檢查有關(guān)的,一個(gè)是越界指針的創(chuàng)建,另外一個(gè)是越界指針的訪問(wèn),也就是通過(guò)越界指針獲取值。在ANSI C([1]3.3.6)中,允許創(chuàng)建指向超過(guò)數(shù)組末尾一個(gè)單元的指針,比如:
int a[10];
f( a + 10 ); // OK
f( a + 11 ); // error
但是上面創(chuàng)建的兩個(gè)指針,都是不能訪問(wèn)的,比如:
int a[10], *p, *q;
p = a + 10; // OK
*p = 0; // Warning (access error)
p[-1] = 0; // No Warning
q = p + 1; // Warning (creation error)
q[0] = 0; // Warning (access error)
布爾條件檢查不象指針檢查那么嚴(yán)格,但是它會(huì)對(duì)恒真的布爾條件產(chǎn)生告警,比如:
if ( n > 0 ) n = 0;
else if ( n <= 0 ) n = -1; // Info 774
上面的代碼會(huì)產(chǎn)生告警(774),因?yàn)榈诙䝼(gè)條件檢查是恒真的,可以忽略。這種冗余代碼不會(huì)導(dǎo)致問(wèn)題,但它的產(chǎn)生通常是因?yàn)檫壿嬪e(cuò)誤或一種錯(cuò)誤可能發(fā)生的征兆,需要詳細(xì)的檢查。

3.2.3 使用assert(斷言)進(jìn)行補(bǔ)救

    在某些情況下,雖然根據(jù)代碼我們可以知道確切的值,但是PC-Lint卻無(wú)法獲取所有情況下變量的值的范圍,這時(shí)候會(huì)產(chǎn)生一些錯(cuò)誤的告警信息,我們可以使用assert語(yǔ)句增加變量取值范圍信息的方法,來(lái)抑制這些錯(cuò)誤的告警信息的產(chǎn)生。下面舉例來(lái)說(shuō)明:
char buf[4];
char *p;
strcpy( buf, "a" );
p = buf + strlen( buf ); // p is 'possibly' (buf+3)
p++; // p is 'possibly' (buf+4)
*p = 'a'; // Warning 661 - possible out-of-bounds reference
PC-Lint無(wú)法知道在所有情況下變量的值是多少。在上面的例子中,產(chǎn)生告警的語(yǔ)句其實(shí)并不會(huì)帶來(lái)什么危害。我們可以直接使用
*p = 'a'; //lint !e661
來(lái)抑制告警。另外,我們還可以使用assert工具來(lái)修正這個(gè)問(wèn)題:
#include <assert.h>
...
char buf[4];
char *p;
strcpy( buf, "a" );
p = buf + strlen( buf );
assert( p < buf + 3 ); // p is 'possibly' (buf+2)
p++; // p is 'possibly' (buf+3)
*p = 'a'; // no problem
由于assert在NDEBUG被定義時(shí)是一個(gè)空操作,所以要保證Lint進(jìn)行的時(shí)候這個(gè)宏沒(méi)有被定義。

    為了使assert()和你的編譯器自帶的assert.h一起產(chǎn)生上面的效果,你需要在編譯選項(xiàng)文件中添加一個(gè)選項(xiàng)。例如,假設(shè)assert 是通過(guò)以下的編譯器宏定義實(shí)現(xiàn)的:
#define assert(p) ((p) ? (void)0 : __A(...))
考慮到__A()會(huì)彈出一個(gè)消息并且不會(huì)返回,所以這個(gè)需要添加的選項(xiàng)就是:
-function( exit, __A )
這個(gè)選項(xiàng)將exit函數(shù)的一些非返回特征傳遞給__A函數(shù)。做為選擇結(jié)果,編譯器可能將assert實(shí)現(xiàn)成一個(gè)函數(shù),例如:
#define assert(k) _Assert(k,...)
為了讓PC-lint知道_Assert是一個(gè)assert函數(shù),你需要使用-function( __assert, _Assert )選項(xiàng)或-function( __assert(1), _Assert(1) )選項(xiàng)復(fù)制__assert()函數(shù)的語(yǔ)義
許多編譯器的編譯選項(xiàng)文件中已經(jīng)存在這些選項(xiàng)了,如果沒(méi)有的話,你可以復(fù)制一個(gè)assert.h文件到PC-lint目錄下(這個(gè)目錄由于使用了-i選項(xiàng),文件搜索的順序優(yōu)先于編譯器的頭文件目錄)。

3.2.4 函數(shù)內(nèi)變量跟蹤

    PC-Lint的函數(shù)值跟蹤功能會(huì)跟蹤那些將要傳遞給函數(shù)(作為函數(shù)參數(shù))變量值,當(dāng)發(fā)生函數(shù)調(diào)用時(shí),這些值被用來(lái)初始化函數(shù)參數(shù)。這種跟蹤功能被用來(lái)測(cè)定返回值,記錄額外的函數(shù)調(diào)用,當(dāng)然還可以用來(lái)偵測(cè)錯(cuò)誤。考察下面的例子代碼:
t1.cpp:
1 int f(int);
2 int g()
3 { return f(0); }
4 int f( int n )
5 { return 10 / n; }
在這個(gè)例子中,f()被調(diào)用的時(shí)候使用0作為參數(shù),這將導(dǎo)致原本沒(méi)有問(wèn)題的10/n語(yǔ)句產(chǎn)生被0除錯(cuò)誤,使用命令lin -u t1.cpp可以得到以下輸出:
--- Module: t1.cpp
During Specific Walk:
File t1.cpp line 3: f(0)
t1.cpp 5 Warning 414: Possible division by 0 [Reference:File t1.cpp: line 3]
你第一個(gè)注意到的事情是短語(yǔ)“During Specific Walk”,緊接著是函數(shù)調(diào)用發(fā)生的位置,函數(shù)名稱以及參數(shù),再下來(lái)就是錯(cuò)誤信息。如果錯(cuò)誤信息中缺少了錯(cuò)誤再現(xiàn)時(shí)的錯(cuò)誤行和用來(lái)標(biāo)記錯(cuò)誤位置的指示信息,這是因?yàn)闄z查到錯(cuò)誤的時(shí)候代碼(被調(diào)用函數(shù)的代碼)已經(jīng)走過(guò)了。如果像下面一樣調(diào)換一下兩個(gè)函數(shù)的位置:
t2.cpp:
1 int f( int n )
2 { return 10 / n; }
3 int g()
4 { return f(0); }
這種情況下就不會(huì)出現(xiàn)被0除的告警,因?yàn)榇藭r(shí)f(0)在第四行,函數(shù)f()的代碼已經(jīng)過(guò)了,在這種情況下就需要引入multi-pass選項(xiàng)。如果在剛才的例子中使用lin -u -passes(2) t2.cpp命令,那么輸出就變成:
--- Module: t2.cpp
/// Start of Pass 2 ///
--- Module: t2.cpp
During Specific Walk:
File t2.cpp line 4: f(0)
t2.cpp 2 Warning 414: Possible division by 0 [Reference:File t2.cpp: line 4]

使用-passes(2)選項(xiàng)將會(huì)檢查代碼兩遍,一些操作系統(tǒng)不支持在命令行中使用-passes(2),對(duì)于這樣的系統(tǒng),可以使用-passes=2 或 -passes[2]代替。通過(guò)冗長(zhǎng)的信息可以看出來(lái),以pass 2開(kāi)始表示第一次檢查沒(méi)有產(chǎn)生告警信息。這一次得到的錯(cuò)誤信息和前一次不同,在某種情況下我們可以推斷出指定函數(shù)調(diào)用的返回值,至少可以得到一些返回值的屬性。以下面的模塊為例:
t3.cpp:
1 int f( int n )
2 { return n - 1; }
3 int g( int n )
4 { return n / f(1); }
使用命令 lin -u -passes(2) t3.cpp,可以得到以下輸出信息:
--- Module: t3.cpp
/// Start of Pass 2 ///
--- Module: t3.cpp

{ return n / f(1); }
t3.cpp 4 Warning 414: Possible division by 0 [Reference:File t3.cpp: lines 2, 4]

第一遍檢查我們知道調(diào)用函數(shù)f()傳遞的參數(shù)是1,第二遍檢查先處理了函數(shù)f(),我們推斷出這個(gè)參數(shù)將導(dǎo)致返回結(jié)果是0,當(dāng)?shù)诙闄z查開(kāi)始處理函數(shù)g()的時(shí)候,產(chǎn)生了被0除錯(cuò)誤。應(yīng)該注意到這個(gè)信息并不是在短語(yǔ)“During Specific Walk”之前出現(xiàn)的,這是因?yàn)殄e(cuò)誤是在對(duì)函數(shù)g()進(jìn)行正常的處理過(guò)程中檢測(cè)到的,此時(shí)并沒(méi)有使用為函數(shù)g()的參數(shù)指定的值。指定的函數(shù)調(diào)用能夠產(chǎn)生附加的函數(shù)調(diào)用,如果我們pass足夠多的檢測(cè)次數(shù),這個(gè)過(guò)程可能會(huì)重復(fù)發(fā)生,參考下面的代碼:
t4.cpp:
1 int f(int);
2 int g( int n )
3 { return f(2); }
4 int f( int n )
5 { return n / f(n - 1); }
第五行的分母f(n-1)并不會(huì)引起懷疑,直到我們意識(shí)到f(2)調(diào)用將導(dǎo)致f(1)調(diào)用,最終會(huì)調(diào)用f(0),迫使最終的返回值是0。使用下面的命令行:
lin -u -passes(3) t4.cpp,
輸出結(jié)果如下:
--- Module: t4.cpp
{ return f(2); }
t4.cpp 3 Info 715: Symbol 'n' (line 2) not referenced
/// Start of Pass 2 ///
--- Module: t4.cpp
/// Start of Pass 3 ///
--- Module: t4.cpp
During Specific Walk:
File t4.cpp line 3: f(2)
File t4.cpp line 5: f(1)
t4.cpp 5 Warning 414: Possible division by 0 [Reference:File t4.cpp: lines 3, 5]
到這里已經(jīng)處理了三遍才檢測(cè)到可能的被0除錯(cuò)誤,想了解為什么需要處理三遍可以看看這個(gè)選項(xiàng)-specific_wlimit(n)。需要注意的是,指定的調(diào)用序列,f(2),f(2),是作為告警信息的序言出現(xiàn)的。

3.3 賦值順序檢查

    當(dāng)一個(gè)表達(dá)式的值依賴于賦值的順序的時(shí)候,會(huì)產(chǎn)生告警564。這是C/C++語(yǔ)言中非常普遍的一個(gè)問(wèn)題,但是很少有編譯器會(huì)分析這種情況。比如
n++ + n
這個(gè)語(yǔ)句是有歧義的,當(dāng)左邊的+操作先執(zhí)行的話,它的值會(huì)比右邊的先執(zhí)行的值大一,更普遍的例子是這樣的:
a[i] = i++;
f( i++, n + i );
第一個(gè)例子,看起來(lái)好像自加操作應(yīng)該在數(shù)組索引計(jì)算以后執(zhí)行,但是如果右邊的賦值操作是在左邊賦值操作之前執(zhí)行的話,那么自加一操作就會(huì)在數(shù)組索引計(jì)算之前執(zhí)行。雖然,賦值操作看起來(lái)應(yīng)該指明一種操作順序,但實(shí)際上是沒(méi)有的。第二個(gè)例子是有歧義的,是因?yàn)楹瘮?shù)的參數(shù)值的計(jì)算順序也是沒(méi)有保證的。能保證賦值順序的操作符是布爾與(&&)或(||)和條件賦值(? :)以及逗號(hào)(,),因此:
if( (n = f()) && n > 10 ) ...
這條語(yǔ)句是正確的,而:
if( (n = f()) & n > 10 ) ...
將產(chǎn)生一條告警。

3.4 弱定義檢查

    這里的弱定義包含是以下內(nèi)容:宏定義、typedef名字、聲明、結(jié)構(gòu)、聯(lián)合和枚舉類型。因?yàn)檫@些東西可能在模塊中被過(guò)多定義且不被使用,PC-Lint有很多消息用來(lái)檢查這些問(wèn)題。PC-Lint的消息749-769 和1749-1769都是保留用來(lái)作為弱定義提示的。
(1) 當(dāng)一個(gè)文件#include的頭文件中沒(méi)有任何引用被該文件使用,PC-Lint會(huì)發(fā)出766告警。
(2) 為了避免一個(gè)頭文件變得過(guò)于大而臃腫,防止其中存在冗余的聲明,當(dāng)一個(gè)頭文件中的對(duì)象聲明沒(méi)有被外部模塊引用到時(shí),PC-Lint會(huì)發(fā)出759告警。
(3) 當(dāng)變量或者函數(shù)只在模塊內(nèi)部使用的時(shí)候,PC-Lint會(huì)產(chǎn)生765告警,來(lái)提示該變量或者函數(shù)應(yīng)該被聲明為static。
    如果你想用PC-Lint檢查以前沒(méi)有檢查過(guò)的代碼,你可能更想將這些告警信息關(guān)閉,當(dāng)然,如果你只想查看頭文件的異常,可以試試這個(gè)命令:
lint -w1 +e749 +e?75? +e?76? ...

3.5 格式檢查

    PC-Lint會(huì)檢查printf和scanf(及其家族)中的格式?jīng)_突,例如:
printf( "%+c", ... )
將產(chǎn)生566告警,因?yàn)榧犹?hào)只在數(shù)字轉(zhuǎn)換時(shí)有用,有超過(guò)一百個(gè)這樣的組合會(huì)產(chǎn)生告警,編譯器通常不標(biāo)記這些矛盾,其他的告警還有對(duì)壞的格式的抱怨,它們是557和567。我們遵循ANSI C建立的規(guī)則,可能更重要的是我們還對(duì)大小不正確的格式進(jìn)行標(biāo)記(包括告警558, 559, 560 和 561)。比如 %d 格式,允許使用int和unsigned int,但是不支持double和long(如果long比int長(zhǎng)),同樣,scanf需要參數(shù)指向的對(duì)象大小正確。如果只是參數(shù)的類型(不是大小)與格式不一致,那將產(chǎn)生626和627告警。-printf 和 -scanf選項(xiàng)允許用戶指定與printf或scanf函數(shù)族類似的函數(shù),-printf_code 和 -scanf_code也可以被用來(lái)描述非標(biāo)準(zhǔn)的 % 碼。

3.6 縮進(jìn)檢查

    根據(jù)代碼中的縮進(jìn)問(wèn)題,PC-Lint也會(huì)產(chǎn)生相應(yīng)的告警,因?yàn)榭s進(jìn)的問(wèn)題有很大一部分是由于代碼結(jié)構(gòu)不良或者大括號(hào)的遺漏造成的。比如下面的例子:
if( ... )
if( ... )
statement
else statement
很明顯這里的else是和第一個(gè)if語(yǔ)句對(duì)應(yīng)的,而在這里編譯器則把它和第二個(gè)if對(duì)應(yīng)起來(lái)。PC-Lint會(huì)對(duì)這種情況產(chǎn)生告警。和這樣的縮進(jìn)檢查相關(guān)的告警主要有三個(gè)725(no positive indentation)、525(negatively indented from)、539(Did not expect positive indentation from Location)要進(jìn)行縮進(jìn)檢查,我們首先要設(shè)置文件中的tab鍵所對(duì)應(yīng)的空格數(shù),默認(rèn)的是占用8個(gè)空格,這個(gè)參數(shù)可以用-t#選項(xiàng)進(jìn)行修改。比如-t4表示tab鍵占用4個(gè)空格長(zhǎng)度。另外,縮進(jìn)檢查還和代碼的編碼格式策略相關(guān),需要進(jìn)行必要的調(diào)整。

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2010-08-08 12:42 |只看該作者
有比較好的規(guī)范, 加上細(xì)心點(diǎn), 一般寫的代碼pclint結(jié)果都應(yīng)該是0 warning, 最多有幾個(gè)info. 所以說(shuō)這工具基本沒(méi)有, 而且用得成本很高, 工程規(guī)模一大, 配置起來(lái)非常費(fèi)勁, 而且老有錯(cuò)誤.

論壇徽章:
0
5 [報(bào)告]
發(fā)表于 2010-08-08 21:19 |只看該作者
very good~~~
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP