pclint 與c++

 

軟件質量對於一個軟件設計者來說是相當重要的。

正確性、健壯性、可靠性、效率、易用性、可讀性(可理解性)、可擴展性、可復
用性、兼容性、可移植性等質量屬性就是軟件整體質量的體現。
軟件質量問題說到底應該是代碼質量問題,寫出優秀、穩定的代碼是一個高水平的程序設計
都應該具備的。

在好的數據結構和算法的前提下,如何編寫出優秀的代碼是我們最應該關心的。

關於如何提高自己編寫的C/C++代碼質量,林銳博士的《高質量C++_C編程指南》是很好的指導!
在那本書的最後提到了PC-Lint代碼審查工具是很好的助手,這裏我簡單的介紹一下這個工具。
下面是從網絡上找來的資料:
/********************************************************************************
LINT工具是一種軟件質量保證工具,許多國外的大型專業軟件公司,如微軟公司,都 
把它作爲程序檢查工具,在程序合入正試版本或交付測試之前一定要保證通過了LINT檢查 
,他們要求軟件工程師在使用LINT時要打開所有的編譯開關,如果一定要關閉某些開關, 
那麼要給出關閉這些開關的正當理由。 

  可想而知,如果從我們編碼後第一次編譯程序時就使用LINT來檢查程序,並且保證消 
除所有的LINT告警,我們就不會遇到象今天這麼多的告警信息。即使在今天,我們如果能 
抽出一定的精力來消除程序中的LINT告警,以後再維持這種無告警狀態就是很容易的了。 
我們程序質量的提高也是不言而喻的。 

  PC-LINT是GIMPEL SOFTWARE公司的產品,其中的內容是非常廣泛的,光是選項就有30 
0多個,涉及到程序編譯及語法使用中的方方面面。本篇培訓材料旨在引導讀者入門,學會 
PC-LINT的基本使用方法,起拋磚引玉的作用,能讓讀者從這裏起步繼續去研究如何嫺熟地 
使用PC-LINT的各種選項,能讓它充分爲我們的開發工作服務。

1.概述 
  如果要給LINT工具下一個形象點的定義,那就是:一種更加嚴格的編譯器。它不僅可 
以象普通編譯器那樣檢查出一般的語法錯誤,還可以檢查出那些雖然完全合乎語法要求, 
但很可能是潛在的、不易發現的錯誤。請看下面的例子: 
1: 
2:char *report( int m, int n, char *p ) 
3:{ 
4: int result; 
5: char *temp; 
6: long nm; 
7: int i, k, kk; 
8: char name[11] = "Joe Jakeson"; 
9: 
10: nm = n * m; 
11: temp = p == "" ? "null" : p; 
12: for( i = 0; i 13: { 
14: k++; 
15: kk = i; 
16: } 
17: 
18: if( k== 1 ) result = nm; 
19: else if( kk > 0 ) result = 1; 
20: else if( kk < 0 ) result = -1; 
21: 
22: if( m == result ) return( temp ); 
23: else return( name ); 
24:} 
  上面的代碼用一般的編譯器編譯是一段有效的代碼,但是用PC-LINT編譯就會有幾個告 
警。首先第8行向name數組賦值時丟掉了nul字符,第10行的乘法精度會失準,第11行的比 
較有問題,第14行的變量k沒有初始化,第15行的kk可能沒有被初始化,第22行的result也 
有可能沒有被初始化,第23行返回的是一個局部對象的地址。這段代碼在大部分編譯器下 
是可以順利編譯通過的,繼續查找其中的錯誤就要靠人工調試程序,如果程序很大,這將 
是一項煩瑣的工作,沒有人可以保證能找出所有的這類問題,但PC-LINT只通過一次簡單的 
編譯就可做到,顯然爲我們節省了大量的開發時間。 

  下面就讓我們看看如何安裝使用PC-LINT。 
2.如何安裝PC-LINT 
  PC-LINT的軟件的安裝過程比較複雜,選項較多,下面根據安裝過程,逐條說明每一步 
的含義。 
0)如果是zip文件,將ZIP安裝文件展開到目錄C:/lint.ins下,進入COMMAND PROMPT,先 
進行目錄映射 subst g: c:/lint.ins,然後轉到G: , 執行install。其他步驟和下面的從 
軟盤安裝是一樣的。 

1)在A:驅插入PC-LINT安裝盤,輸入A:/>install命令,進入開始安裝欄,按任意鍵繼續, 
進入PC-LINT介紹欄,再按任意鍵繼續。 
2)進入環境選擇欄,這一欄中有三個選項: 
Windows NT/Windows 95 
MS-DOS(DOS extended) 
OS/2(32bit) 
如果計算機安裝了WIN95、WIN97、WIN98或WINNT要選擇Windows NT/Windows 95,如果 
只有DOS則選擇DOS。 
3)進入安裝目錄選擇欄,它推薦的是C:/>LINT,如不想安裝在這個目錄下,可輸入自己想 
要安裝的目錄,然後按回車確認,如果要安裝的目錄不存在,它會提示爲你建立這個目錄 
。我們這裏選C:/>LINT 
4)選擇安裝盤所在的磁盤驅動器,我們這裏選A: 
5)判斷是否要選擇多種編譯器或編譯庫的配置,如果要對不同編譯環境下的程序進行L 

INT,則選YES,否則選NO。然後回車確認。 
6)這時看到一個編譯器列表,在這個表中選擇自己使用的編譯器,如果表中沒有自己使用 
的編譯器,可選擇通用編譯器:Generic Compilers。按回車確認。這個選項會體現在co- 
xxx.lnt文件中。 
7)接着安裝程序會讓你選擇一個的內存模型,可以根據自己程序區和數據區的實際大小選 
擇一個恰當的內存模型。如果CPU爲32位68K系列,則要選擇:32-bit Flat Module。 
內存模型的選項會體現在STD.LNT文件中。 
8)選完內存模型後,會看到一個庫類型的列表,在這裏選擇一個或多個編譯時使用的庫。 
這個選項會體現在LIB-xxx.LNT文件中。 
9)接着是讓你選擇爲使用C++編程提出過重要建議的作者,選擇的某作者後,他提出的編 
程建議方面的選項將被打開。與作者選擇有關的選項會體現在AU-xxx.LNT文件中。 
10)下一步是設置包含文件目錄。有兩種選項,第一種是使用環境變量INCLUDE,環境變量 
在批處理文件中設置,環境變量後每個目錄用分號隔開,例如可設成“INCLUDE=C:/MRI/M 
CC68K;D:/LAP/SRC/INC”。第二種選項是使用-i選項,-i選項體現在STD.LNT文件中,每個 
目錄前以-I引導,目錄間以空格分隔,例如可設成“-IC:/MRI/MCC68K -ID:/LAP/SRC/INC 
”。如果選擇使用-I選項,安裝程序會接着讓你輸入包含文件所在的目錄。 
11) 如果前面選擇了使用多個編譯環境,這裏將會問你是否選擇更多的編譯環境,如果選 
YES,將會從第6步開使重複。如果選NO則會結束編譯器選擇。 
12)接下來將會準備產生一個 反映全局編譯信息顯示情況的選項文件OPTIONS.LNT,該文 
件的產生方式有兩種,一種是安裝程序對幾個核心選項逐一解釋並提問你是否取消該選項 
,如果你選擇取消,則會體現在OPTIONS.LNT文件中,具體體現方式是在該類信息編碼前加 
-e,後面第13~18步是逐一選擇核心選項的過程。如果選擇第二種選擇方式,安裝文件會先 
生成一個空的OPTIONS.LNT文件,等你以後在實際應用時加入必要的選項。 
13)是否關閉賦值時的布爾測試告警,如:if(a=f()){... 
14)是否關閉賦值時的有符號量和無符號量間的不匹配告警,通常情況下,這種賦值不會 
帶來問題,選擇關閉該告警信息的同時,其他類型的有符號量和無符號量間混合操作的告 
警仍然是打開的。 
15)當把一個整形量賦值給一個比它短的量時,後者會丟失精度,例如把一個INT量賦值給 
給一個CHAR量。本步是讓你選擇是否關閉該類告警。 
16)是否關閉左移帶符號量的告警。通常PC-LINT會對所有帶符號量的移動產生告警,但右 
移一般是由不同的CPU來確定是否將符號位移入,左移一般是不會產生什麼問題的,所以可 
以選擇關閉該告警。 
17)在一個C函數被定義或聲明前調用它,並不總是會產生錯誤,在這裏可以選擇是否關閉 
該告警選項。該選項對C++程序不起作用。 
18)是否關閉“調用不存在的函數原型”告警。有些程序員不願遵守嚴格的函數原形定義 
約定,但PC-LINT會在調用一個沒有定義的函數原型時產生一個告警,在這裏可以選擇關閉 
該告警。 
19)通過上面的步驟確定OPTIONS.LNT文件的形式後,接着是選擇編譯環境。PC-LINT提供 
了集成在多種開發環境中工作的功能,例如可集成在VC、BC、Source Insight中。假如我 
們在這裏選擇Source Insight。選擇後安裝程序會繼續問你是否還選擇其它的環境,可根 
據自己應用的實際情況選擇一種或多種開發環境。開發環境的選擇情況記錄在env-xxx.ln 
t文件中。 
20)安裝程序會生成一個LIN.BAT文件,該文件是運行PC-LINT的批處理文件,爲了使該文 
件能在任何路徑下運行,安裝程序提供了兩種方法供你選擇。第一種方法是讓你選擇把LI 
N.BAT拷貝到任何一個PATH目錄下,在安裝結束運行LCOPY.BAT文件時,會把LIN.BAT拷貝到 
你指定的目錄。第二種方法是生成一個LSET.BAT文件,在每次使用PC-LINT前先運行它來設 
置路徑,或者把LSET.BAT文件的內容拷貝到AUTOEXEC.BAT文件中。 
21)在安裝程序執行完後第一件事是在你安裝的目錄下執行LCOPY.BAT文件。它會從安裝盤 
拷貝將一些文件拷貝到安裝目錄下,並根據你在安裝過程中的選擇來設置文件中的參數。 

3.LINT 一個C文件 
3.1用命令行方式進行LINT 
如果使用LIN.BAT批處理文件進行LINT,在LINT前要先看一下該批處理文件中的內容,裏面 
包含了LINT-NT命令和命令選項,可以根據自己的要求來修改、增減選項。我們看到,在這 
個批命令中嵌套了一個std.lnt文件,在std.lnt文件中還嵌套了co.lnt、options.lnt和l 
ib-stl.lnt文件,原則上*.lnt文件是可以無限制嵌套,該類文件中一般都是了LINT的選項 
,可通過修改這些文件來修改LINT選項,選項是按照從左到右的順序執行的。可執行下面 
命令行: 
C:/abc/src>lin alpha.c beta.c gamma.c 
通常對於由多個C模塊組成的程序,最好先分別對每個C模塊單元進行LINT檢查,做單元LI 
NT時可如下運行: 
C:/abs/src>lin -u alpha.c 
其中-u是單元選項,使用-u後可以關閉一些檢查多模塊時會產生的告警,例如“函數未被 
使用”或“函數沒有定義”等。 
也可以不使用LIN.BAT批處理文件,而直接使用LINT命令。在DOS環境下LINT命令爲LINT.E 
XE,在Windows95/NT環境下爲LINT-NT.EXE,在OS2環境下爲LINT-OS2.EXE。直接使用LINT 
命令要注意的一點是要在使用前預先設置LINT目錄所在路徑,最好的方法是把該路徑加在 
AUTOEXEC.BAT文件中。其它的使用方法與使用批處理文件相同。例如: 
C:/abs/src>lint-nt -ic:/lint/ std.lnt -os(_lint.tmp) *.c 
3.2用開發環境進行LINT 
也可以使用開發環境來執行LINT操作,一般開發環境都支持運行可執行文件,但不一定支 
持運行批處理文件,下面用Source Insight , Ultra Edit, MSVC 6.0 來舉例說明如何在 
開發環境下進行LINT。 
3.2.1 在Source Insight中集成 
如果你在安裝過程中選定了使用某個開發環境,安裝程序會在你安裝的目錄下生成一個en 
v-xxx.lnt的文件,例如選擇了Source Insight就會有一個env-si.lnt文件。用編輯器打開 
該文件,在該文件開始的註釋中說明了如何將PC-LINT功能集成在開發環境中,集成在Sou 
rce Insight中的過程如下: 
1)從Options菜單中選擇“Custom Commands”命令項。 
2)在Name欄中輸入“PC-lint ”,原則上這個名稱可以隨便起,只要你能搞清楚它的含義 
就可以了。 
3)在Run欄中輸入“c:/lint/lint-nt -u -ic:/lint std env-si %f”其中c:/lint是你P 
C-LINT的安裝目錄。 
4)在Output欄中選擇“Iconic Window”、“Capture Output”。 
5)在Control欄中選擇“Save Files First”。 
6)在Source Links in Output欄中選擇“Parse Links in Output”、“File,then Lin 
e”。 
7)在Pattern欄中輸入“^/([^ ]*/) /([0-9]+/)”。 
8)點Add鍵加入該命令。如下圖: 
9)使用時,在Source Insight下打開要LINT的文件,打開Options菜單中的“Custom Com 
mands”命令項,在“Command”欄中選擇“PC-lint unit check”命令運行即可。 
注意到我的Run一欄的參數和上面的提示不一樣,其實我的其他古怪參數都放到c:/lint/s 
td.lnt中了。請注意,不論你怎樣配置參數一定不要忘記了將si-env.lnt包含在你的配置 
文件裏,否則就無法進行錯誤信息和程序的自動對應了。 
爲了使用方便,你還可以配置一下Menu按鈕,將它加到系統菜0單裏,這屬於一般性的 
Source Insight應用,筆者就不在此贅述了。 
第二筆者在NT中使用Source Insight時,好象集成不了,原因暫時不明瞭。上面的例子在 
WIN 95下測試成功。 
如果要修改LINT選項,可直接在Run欄中修改,也可專門編輯一個*.lnt文件放在c:/lint目 
錄下,並將該文件名加入Run欄中,和命令行方式是一樣的。 
3.2.2在Ultra Editor中集成 
選取 Menu | Advanced | Tool Configuration ... , 顯示如下圖: 
1)點按“Insert", 
2)在command line:中填寫:c:/lint/lint-nt c:/lint/std.lnt %f 
3)在Menu Item中填寫:PC-LINT 
4)在Command Output中選擇: (x) Output to List Box 和 (x) Capture Output 
5)點按"OK" 
如圖所示的配置筆者在UE6.0 / NT 4.0 下測試成功。 
3.2.3 在MSVC 6.0中集成 

//這個好使過
基本原理是一樣的: 
1)選取 menu | tools | customize..... 
2)選取 Tools Tab: 
3)點按主對話框上方的虛線小方框 New a tool item 
4)輸入 name: PC-LINT 
5)輸入 Command: c:/lint/lint-nt.exe 
6)輸入 Arguments: c:/lint/std.lnt $(FilePath)  //注:替std.lnt爲lnt/env-vc6.lnt
7) 選擇 (x) Use Output Window 
8)Close 
完成後,在tools菜單下就會有一項PC-LINT選項。 
下面是筆者在VC6 / Win NT 4.0 的情況下的TOOL配置圖: 
3.3LINT選項 
LINT選項可以放在註釋中,例如: 
/*lint option1 option2 ... optional commentary */ 
//lint option1 option2 ... optional commentary 
選項間要以空格分開,lint命令一定要小寫,並且緊跟在/*或//後面,不能有空格。如果 
選項由類似於操作符和操作數的部分組成,例如-esym(534, printf, scanf, operat or 
new),其中最後一個選項是operator new,那麼在operator和new中間只能有一個空 
格。 
選項還可以放在宏定義中,例如: 
#define DIVZERO(x) /*lint -save -e54 */ ((x) /o) /*lint -restore */ 
LINT的選項很多共有300多種,大體可分爲以下幾類: 
1)錯誤信息禁止選項 
該類選項是用於禁止生成某類錯誤信息的選項,最常用的是-e和+e,-e是禁止生成某類錯 
誤信息,+e是恢復生成某類錯誤信息。運行lint目錄下的msg.exe可以得到msg.txt文件, 
這個長達5000行的文件包含了所有的錯誤信息號和解釋。 
-w 對於所有大於級別的告警信息都不顯示。 
-wlib()對於所有大於級別的關於庫函數數的告警信息都不顯示。我們可以用-wlib(0)來屏 
蔽所有的庫函數的告警信息,-wlib(1)只顯示庫函數中的句法錯誤。 
-esym(#,) 可以屏蔽對於特定符號的某告警信息。 
2)變量類型大小選項 
不同的目標機、編譯系統變量類型的的大小(如短整形變量、整形變量等)會有所不同, 
該類選項用於爲目標機設置變量類型的大小。由於默認的設置與大部分的編譯器是匹配的 
,這些專門的設置通常情況下是不需要的,只在特別的目標機結構中才用。例如一個M680 
00目標機,它的int類型和指針類型通常是32bit的,這時你應該使用選項:-si4 
-sp4。這些尺寸參數的當前值可以通過help屏來獲得,例如可以輸入以下命令行: 
lin -si4 -sp4 ? 
3)冗長信息選項 
冗長信息指的是LINT過程中產生的一些與編譯過程有關的信息,而不是真正的告警信息、 
錯誤信息等。是否生成這些信息可以通過-v和+v選項來決定。+v是生成這些信息,-v是關 
閉這些信息,這組選項中除+v外,其它所有選項都可以關閉+v選項。 
4)標記選項 
以+f、++f、-f和--f開頭的選項是標記選項。他們的邏輯含義分別如下: 
+f...:通過把標誌置爲1而把它置爲ON 
-f...:通過把標誌置爲0而把它置爲OFF 
++f...:標誌增1 
--f...:標誌減1 
後面兩個用於你想在局部把一個標誌置爲ON的情況,而不影響全局設置。例如你可以這樣 
使用: 
/*lint ++flb */ 
int printf( ); 
/*lint --flb */ 
標記選項的種類很多,基本含義是用於打開或關閉某類語法情況使用,例如允許使用縮寫 
結構體名稱,允許使用無名聯合體,把所有模塊當作C++編譯等。 
5)消息顯示選項 
消息顯示選項用於定義消息輸出格式。主要有消息高度選項、消息寬度選項、消息格式選 
項等。 
6)其它選項 
其它選項中的種類很多,各種類間差異很大,在這裏就不一一介紹了,建議大家看一看《 
PC-LINT》一書,第五章有對每種選項的詳細說明。lint本身也有一些說明信息, lint-n 
t 2> lint.txt 然後狂按幾個回車就可以生成一個lint選項的說明文件。 
4.LINT一個工程下的多個C文件 
4.1爲何要LINT多個C文件 
在程序編碼初期,我們關心的可能只是單個C模塊種中的語法問題,等到編程後期,對於由 
多個C模塊組成的程序,我們希望瞭解當把多個模塊連接在一起後是否還有存在於模塊間的 
語法問題。這時編譯器雖然能給出一些告警,但PC-LINT的連接能給出更多的告警。還有當 
我們能保證其中的幾個模塊相對穩定,而另外幾個模塊仍有問題時可以先將幾個穩定的模 
塊編譯連接成一個目標文件,文件每次修改完成後先單獨編譯,然後連接入總的目標文件 
。 
4.2如何LINT一個工程下的多個C文件 
象我們平時使用的編譯工具一樣,PC-LINT在編譯連接多個C文件時也會先把每個C文件編譯 
生成中間的目標文件*.lob,然後再將所有的LOB文件連接在一起。LOB是Lint Object Mod 
ule的縮寫。這個文件中包含了一個C或C++模塊的所有外部信息。生成LOB文件時有三種選 
項要注意:第一種是-u,如果要LINT生成LOB文件,就一定要加-u選項;第二種是-zero或 
-zero(500)選項,爲了保證LOB文件在模塊存在錯誤的情況下也能生成,就一定要加這個選 
項;第三種是-oo[(filename)],filename是生成的LOB文件的名稱,在-oo後面,可加,也 
可不加,如不加,則LOB文件名與原C模塊的名稱相同,例如: 
lint -u alpha.c -oo(a1) 
生成的LOB文件名爲:a1.lob 
lint -u alpha.c -oo 
生成的LOB文件名爲:alpha.lob 
LINT一個工程下的多個C模塊,在用戶的源程序目錄下一般需要三個文件: 一個選項文件 
(*.lnt)、一個批處理文件(*.bat)和一個MAKEFILE文件(*.mak)。下面一一講述如何 
製作這些文件。 
1)選項文件(*.lnt) 
選項文件在前面也提到過,你可以把你LINT每個C文件時時用到的所有公共選項羅列在該文 
件中,選項生效的順序按照從左到右,從上到下的原則。該類文件可以層層嵌套,嵌套的 
層數沒有限制。例如make.lnt文件: 
-iC:/lint 
std.lnt 
+os(temp) 
-e46 
+vm 
-zero 
2)批處理文件(*.bat) 
製作批處理文件時要注意要在該文件中調用TCMAKE.EXE文件和MAKEFILE文件,例如lintma 
ke.mak文件: 
@echo Lint Making 'makelap': 
tcmake -flintmake.mak 
@echo End of making 
3)MAKEFILE文件(*.mak) 
MAKEFILE使用的TCMAKE的語法,和我們平時開發編譯時使用的MAKEFILE文件語法格式一樣 
,例如下面的lintmake.mak文件: 
MCCPATH = c:/mcc68k 
OPTION = -u make.lnt -oo 
GLOBLE = os.h l2lap.h 
mail_depend = $(GLOBLE) q931.h mail.h 
lapmain_depend = $(GLOBLE) l1pubdef.h q931.h mail.h 
lapos_depend = $(GLOBLE) 
fhdlc1_depend = $(GLOBLE) cpuhdlc.h bd_prar.h q931.h 
OBJ = mail.lob lapmain.lob lapos.lob fhdlc1.lob 
project.lob : $(OBJ) 
lint-nt make.lnt -e768 -e769 *.lob 
mail.lob: mail.c $(mail_depend) 
lint-nt $(OPTION) mail.c 
lapmain.lob: lapmain.c $(lapmain_depend) 
lint-nt $(OPTION) lapmain.c 
lapos.lob: lapos.c $(lapos_depend) 
lint-nt $(OPTION) lapos.c 
fhdlc1.lob: fhdlc1.c $(fhdlc1_depend) 
lint-nt $(OPTION) fhdlc1.c 
4.3簡單的LINT多個文件 
假設我們的工程不復雜,我們可以負擔起每次都將所有的文件都lint一遍的開銷,也可以 
不使用上面的正規用法。筆者在實踐中發現,將所有的*.c文件放在一個lint命令中,同樣 
能完成lint整個工程的目的。 
如: 
lint-nt c:/lint/std.lnt AllMySource.lnt 
在AllMySource.lnt中包括你的工程中的所有源文件: 
a1.c 
a2.c 
a3.c 
需要注意的是,在std.lnt文件中就不需要-u選項了。因爲我們已經提供了所有的信息。

在大概看完了上述資料後,就可以把這個工具正式用於我們的程序了。
將該工具集成到VC++裏是最常用到的,在網上也可以找到很多相關資料。
現在我簡單的講一下將它集成到Editpuls裏,因爲我比較喜歡用純文本編輯器寫代碼,呵呵!

還是先看看網上的關於這方面的資料:-P
               http://xyzboard.com/?q=node/58

現在我寫下我的經驗:
在上述資料裏有一些要修改的地方。

首先要注意Unix下xargs命令的使用。一定要給全路徑!
比如我的是這樣設參數項的:
$(FilePath) -name *.c -o -name *.cpp | D:/UnxUtils/usr/local/wbin/xargs
D:/Sources/PC-Lint/lint-nt -i"D:/UnxUtils/usr" -u D:/Sources/PC-Lint/std.lnt
D:/Sources/PC-Lint/env-vc6.lnt -w
也就是說xargs後的路徑要給全。。。。

再有就是在編寫std.lnt文件的時候要注意的,這個是我的std.lnt文件:
D:/Sources/PC-Lint/co-msc60.lnt

D:/Sources/PC-Lint/lib-w32.lnt

D:/Sources/PC-Lint/options.lnt -si4 -sp4

-i"D:/Microsoft Visual Studio 8;D:/Microsoft Visual Studio 8/VC/include"

-wlib(0)

最後的-wlib(0)是取消對編譯器庫文件的審查,這個是相當重要的一個參數。如果
你只是想審查自己的代碼的話,請加上這個參數。不然,就會對編譯器的庫函數也
進行審查。。。。想看看庫文件的可以研究一下,呵呵!
好了,現在你就可以對自己的代碼進行摸底咯~~~~

下面這個是我的一個數據結構的實驗:Complex的代碼
/**********************************************************************

  File name: Complex.h       
  Function: The description of complex class    
  Platform: Win Xp SP2       
  Compiler & Linker: CL.exe 8.0 (in Visual Studio 2005 SDK)         
  Programmer: 88250       
  Complete date: September 7, 2006    Version: 1.0   
  Blog: http://DL88250.ynutx.net     
  E-mail: [email protected]      
  QQ: 845765 or 316281008      
  
 **********************************************************************/

#i nclude <iostream>

using namespace std;

class complex
{
    public: // public interface
  complex(double r, double i); // constructor
  void assign(void); // user input to define a complex
  // overload operators to friend functions
  friend complex operator + (complex &c1, complex &c2); 
  friend complex operator - (complex &c1, complex &c2);
  friend complex operator * (complex &c1, complex &c2);
  friend complex operator / (complex &c1, complex &c2);
  friend ostream& operator << (ostream &out, complex x);
 private:
  double real;
  double imag;
};

/**********************************************************************
 
  File name: Complex.h       
  Function: A simple complex calculator demo    
  Platform: Win Xp SP2       
  Compiler & Linker: CL.exe 8.0 (in Visual Studio 2005 SDK)   
  Programmer: 88250       
  Complete date: September 7, 2006    Version: 1.0   
  Blog: http://DL88250.ynutx.net     
  E-mail: [email protected]      
  QQ: 845765 or 316281008      
      
 **********************************************************************/

#i nclude "Complex.h"

complex::complex(double r = 0.0, double i = 0.0)
{
 real = r;
 imag = i;
 return;
}

void complex::assign(void)
{
 cout << "Please input the real part : " << endl;
 cin >> real;
 cout << "Please input the imaginary part: " << endl;
 cin >> imag;

 return;
}
ostream& operator << (ostream &out, complex x)
{
 if (x.imag < 0)
 {
  return (out << x.real << " + " << "(" << x.imag << ")" << "i" <<
endl);
 }
 else
 {
  return (out << x.real << " + " << x.imag << "i" << endl);  
 }

complex operator + (complex &c1, complex &c2)
{
 return complex(c1.real + c2.real, c1.imag + c2.imag); 
}

complex operator - (complex &c1, complex &c2)
{
 return complex(c1.real - c2.real, c1.imag - c2.imag); 
}

complex operator * (complex &c1, complex &c2)
{
 return complex((c1.real * c2.real - c1.imag * c2.imag)
       ,(c1.real * c2. imag + c2.real * c1.imag)); 
}

complex operator / (complex &c1, complex &c2)
{
 double denominator = c2.real * c2.real + c2.imag * c2.imag;
 return complex((c1.real * c2.real + c1.imag * c2.imag) / denominator
       ,(c1.imag * c2.real - c1.real * c2.imag) /
denominator); 
}

int main(void)
{
 complex c1(5, 4), c2(2, 10);
 
 cout << "c1 = " << c1;
 cout << "c2 = " << c2;

 cout << "c1 + c2 = " << c1 + c2;
 cout << "c1 - c2 = " << c1 - c2;
 cout << "c1 * c2 = " << c1 * c2;
 
 c1.assign();
 cout << "Current c1 = " << c1;
 c2.assign();
 cout << "Current c2 = " << c2;
 cout <<"c1 / c2 = " << c1 / c2;

 return 0;
}

現在用PC-Lint審查一下:

PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001

--- Module:   D:/Sources/C++/DataStructure/Exp1/Complex.cpp
};
D:/Sources/C++/DataStructure/Exp1/Complex.h(33): error 1712: (Info -- default co
nstructor not defined for class 'complex')
*/

D:/Sources/C++/DataStructure/Exp1/Complex.h(70): error 783: (Info -- Line does n
ot end with new-line)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(44): error 1746: (Info -- paramete
r 'x' in function 'operator<<(std::basic_ostream<char,std::char_traits<char>> &,
 complex)' could be made const reference)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(49): error 1764: (Info -- Referenc
e parameter 'c1' (line 46) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(46): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(49): error 1764: (Info -- Referenc
e parameter 'c2' (line 46) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(46): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(54): error 1764: (Info -- Referenc
e parameter 'c1' (line 51) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(51): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(54): error 1764: (Info -- Referenc
e parameter 'c2' (line 51) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(51): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(60): error 1764: (Info -- Referenc
e parameter 'c1' (line 56) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(56): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(60): error 1764: (Info -- Referenc
e parameter 'c2' (line 56) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(56): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(68): error 1764: (Info -- Referenc
e parameter 'c1' (line 62) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(62): error 830: (Info -- Location
cited in prior message)
}
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(68): error 1764: (Info -- Referenc
e parameter 'c2' (line 62) could be declared const ref)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(62): error 830: (Info -- Location
cited in prior message)
    complex c1(5, 4), c2(2, 10);
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(72): error 747: (Info -- Significa
nt prototype coercion (arg. no. 1) int to double)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(72): error 747: (Info -- Significa
nt prototype coercion (arg. no. 2) int to double)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(72): error 747: (Info -- Significa
nt prototype coercion (arg. no. 1) int to double)
D:/Sources/C++/DataStructure/Exp1/Complex.cpp(72): error 747: (Info -- Significa
nt prototype coercion (arg. no. 2) int to double)
}

D:/Sources/C++/DataStructure/Exp1/Complex.cpp(88): error 783: (Info -- Line does
 not end with new-line)

--- Global Wrap-up

 error 1754: (Info -- Expected symbol 'operator*=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator+=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator-=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator/=' to be declared for class 'com
plex')
 error 900: (Note -- Successful completion, 28 messages produced)
請按任意鍵繼續. . .

哎。。。。問題好多。。。。

改了下代碼:
/**********************************************************************

  File name: Complex.h       
  Function: The description of complex class    
  Platform: Win Xp SP2       
  Compiler & Linker: CL.exe 8.0 (in Visual Studio 2005 SDK)         
  Programmer: 88250       
  Complete date: September 7, 2006    Version: 1.0   
  Blog: http://DL88250.ynutx.net     
  E-mail: [email protected]      
  QQ: 845765 or 316281008      
  
 **********************************************************************/

#i nclude <iostream>

using namespace std;

class complex
{
    public: // public interface
  complex(double r, double i); // constructor
  complex(void); // void constructor
  void assign(void); // user input to define a complex
  // overload operators to friend functions
  friend complex operator + (const complex &c1,
        const complex &c2); 
  friend complex operator - (const complex &c1,
        const complex &c2);
  friend complex operator * (const complex &c1,
        const complex &c2);
  friend complex operator / (const complex &c1,
        const complex &c2);
  friend ostream& operator << (ostream &out, const complex &x);
 private:
  double real;
  double imag;
};

/**********************************************************************
 
  File name: Complex.h       
  Function: A simple complex calculator demo    
  Platform: Win Xp SP2       
  Compiler & Linker: CL.exe 8.0 (in Visual Studio 2005 SDK)   
  Programmer: 88250       
  Complete date: September 7, 2006    Version: 1.0   
  Blog: http://DL88250.ynutx.net     
  E-mail: [email protected]      
  QQ: 845765 or 316281008      
      
 **********************************************************************/

#i nclude "Complex.h"

complex::complex(void)
{
 real = 0;
 imag = 0;

 return;
}

complex::complex(double r = 0.0, double i = 0.0)
{
 real = r;
 imag = i;
 return;
}

void complex::assign(void)
{
 cout << "Please input the real part : " << endl;
 cin >> real;
 cout << "Please input the imaginary part: " << endl;
 cin >> imag;

 return;
}
ostream& operator << (ostream &out, const complex &x)
{
 if (x.imag < 0)
 {
  return (out << x.real << " + " << "(" << x.imag << ")" << "i" <<
endl);
 }
 else
 {
  return (out << x.real << " + " << x.imag << "i" << endl);  
 }

complex operator + (const complex &c1, const complex &c2)
{
 return complex(c1.real + c2.real, c1.imag + c2.imag); 
}

complex operator - (const complex &c1, const complex &c2)
{
 return complex(c1.real - c2.real, c1.imag - c2.imag); 
}

complex operator * (const complex &c1, const complex &c2)
{
 return complex((c1.real * c2.real - c1.imag * c2.imag)
       ,(c1.real * c2. imag + c2.real * c1.imag)); 
}

complex operator / (const complex &c1, const complex &c2)
{
 double denominator = c2.real * c2.real + c2.imag * c2.imag;
 return complex((c1.real * c2.real + c1.imag * c2.imag) / denominator
       ,(c1.imag * c2.real - c1.real * c2.imag) /
   denominator); 
}

int main(void)
{
 complex c1(5.0, 4.0), c2(2.0, 10.0);
 
 cout << "c1 = " << c1;
 cout << "c2 = " << c2;

 cout << "c1 + c2 = " << c1 + c2;
 cout << "c1 - c2 = " << c1 - c2;
 cout << "c1 * c2 = " << c1 * c2;
 
 c1.assign();
 cout << "Current c1 = " << c1;
 c2.assign();
 cout << "Current c2 = " << c2;
 cout <<"c1 / c2 = " << c1 / c2;

 return 0;
}


現在好多了:

PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001

--- Module:   D:/Sources/C++/DataStructure/Exp1/Complex.cpp

--- Global Wrap-up

 error 1754: (Info -- Expected symbol 'operator*=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator+=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator-=' to be declared for class 'com
plex')
 error 1754: (Info -- Expected symbol 'operator/=' to be declared for class 'com
plex')
D:/Microsoft Visual Studio 8/VC/include/xutility(873): error 628: (Warning -- no
 argument information provided for function 'std::__is_base_of()' (line 873, fil
e D:/Microsoft Visual Studio 8/VC/include/xutility))
 error 900: (Note -- Successful completion, 5 messages produced)
請按任意鍵繼續. . .

關於剩下的問題可以參看PC-Lint目錄下的msg.txt文件,裏面有詳細的解釋。。。。
哎。。。。閃人咯~~~~
:-P

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章