LINT工具是一種軟件質(zhì)量保證工具 , 許多國外的大型專業(yè)軟件公司,如微軟公司,都把它作為程序檢查工具,在程序合入正試版本或交付測試之前一定要保證通過了LINT檢查,他們要求軟件工程師在使用LINT時(shí)要打開所有的編譯開關(guān),如果一定要關(guān)閉某些開關(guān),那么要給出關(guān)閉這些開關(guān)的正當(dāng)理由。
可想而知,如果從我們編碼后第一次編譯程序時(shí)就使用LINT來檢查程序,并且保證消除所有的LINT告警,我們就不會遇到象今天這么多的告警信息。即使在今天,我們?nèi)绻艹槌鲆欢ǖ木硐绦蛑械腖INT告警,以后再維持這種無告警狀態(tài)就是很容易的了。我們程序質(zhì)量的提高也是不言而喻的。
PC-LINT是GIMPEL SOFTWARE公司的產(chǎn)品,其中的內(nèi)容是非常廣泛的,光是選項(xiàng)就有300多個,涉及到程序編譯及語法使用中的方方面面。本篇培訓(xùn)材料旨在引導(dǎo)讀者入門,學(xué)會PC-LINT的基本使用方法,起拋磚引玉的作用,能讓讀者從這里起步繼續(xù)去研究如何嫻熟地使用PC-LINT的各種選項(xiàng),能讓它充分為我們的開發(fā)工作服務(wù)。
1.概述 如果要給LINT工具下一個形象點(diǎn)的定義,那就是:一種更加嚴(yán)格的編譯器。它不僅可以象普通編譯器那樣檢查出一般的語法錯誤,還可以檢查出那些雖然完全合乎語法要求,但很可能是潛在的、不易發(fā)現(xiàn)的錯誤。請看下面的例子: 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數(shù)組賦值時(shí)丟掉了nul字符,第10行的乘法精度會失準(zhǔn),第11行的比較有問題,第14行的變量k沒有初始化,第15行的kk可能沒有被初始化,第22行的result也有可能沒有被初始化,第23行返回的是一個局部對象的地址。這段代碼在大部分編譯器下是可以順利編譯通過的,繼續(xù)查找其中的錯誤就要靠人工調(diào)試程序,如果程序很大,這將是一項(xiàng)煩瑣的工作,沒有人可以保證能找出所有的這類問題,但PC-LINT只通過一次簡單的編譯就可做到,顯然為我們節(jié)省了大量的開發(fā)時(shí)間。
下面就讓我們看看如何安裝使用PC-LINT。 2.如何安裝PC-LINT PC-LINT的軟件的安裝過程比較復(fù)雜,選項(xiàng)較多,下面根據(jù)安裝過程,逐條說明每一步的含義。 0)如果是zip文件,將ZIP安裝文件展開到目錄C:\lint.ins下,進(jìn)入COMMAND PROMPT,先進(jìn)行目錄映射 subst g: c:\lint.ins,然后轉(zhuǎn)到G: , 執(zhí)行install。其他步驟和下面的從軟盤安裝是一樣的。
1)在A:驅(qū)插入PC-LINT安裝盤,輸入A:\>install命令,進(jìn)入開始安裝欄,按任意鍵繼續(xù),進(jìn)入PC-LINT介紹欄,再按任意鍵繼續(xù)。 2)進(jìn)入環(huán)境選擇欄,這一欄中有三個選項(xiàng): Windows NT/Windows 95 MS-DOS(DOS extended) OS/2(32bit) 如果計(jì)算機(jī)安裝了WIN95、WIN97、WIN98或WINNT要選擇Windows NT/Windows 95,如果 只有DOS則選擇DOS。 3)進(jìn)入安裝目錄選擇欄,它推薦的是C:\>LINT,如不想安裝在這個目錄下,可輸入自己想要安裝的目錄,然后按回車確認(rèn),如果要安裝的目錄不存在,它會提示為你建立這個目錄。我們這里選C:\>LINT 4)選擇安裝盤所在的磁盤驅(qū)動器,我們這里選A: 5)判斷是否要選擇多種編譯器或編譯庫的配置,如果要對不同編譯環(huán)境下的程序進(jìn)行L INT,則選YES,否則選NO。然后回車確認(rèn)。 6)這時(shí)看到一個編譯器列表,在這個表中選擇自己使用的編譯器,如果表中沒有自己使用的編譯器,可選擇通用編譯器:Generic Compilers。按回車確認(rèn)。這個選項(xiàng)會體現(xiàn)在co-xxx.lnt文件中。 7)接著安裝程序會讓你選擇一個的內(nèi)存模型,可以根據(jù)自己程序區(qū)和數(shù)據(jù)區(qū)的實(shí)際大小選擇一個恰當(dāng)?shù)膬?nèi)存模型。如果CPU為32位68K系列,則要選擇:32-bit Flat Module。 內(nèi)存模型的選項(xiàng)會體現(xiàn)在STD.LNT文件中。 8)選完內(nèi)存模型后,會看到一個庫類型的列表,在這里選擇一個或多個編譯時(shí)使用的庫。這個選項(xiàng)會體現(xiàn)在LIB-xxx.LNT文件中。 9)接著是讓你選擇為使用C++編程提出過重要建議的作者,選擇的某作者后,他提出的編程建議方面的選項(xiàng)將被打開。與作者選擇有關(guān)的選項(xiàng)會體現(xiàn)在AU-xxx.LNT文件中。 10)下一步是設(shè)置包含文件目錄。有兩種選項(xiàng),第一種是使用環(huán)境變量INCLUDE,環(huán)境變量在批處理文件中設(shè)置,環(huán)境變量后每個目錄用分號隔開,例如可設(shè)成“INCLUDE=C:\MRI\MCC68K;D:\LAP\SRC\INC”。第二種選項(xiàng)是使用-i選項(xiàng),-i選項(xiàng)體現(xiàn)在STD.LNT文件中,每個目錄前以-I引導(dǎo),目錄間以空格分隔,例如可設(shè)成“-IC:\MRI\MCC68K -ID:\LAP\SRC\INC”。如果選擇使用-I選項(xiàng),安裝程序會接著讓你輸入包含文件所在的目錄。 11) 如果前面選擇了使用多個編譯環(huán)境,這里將會問你是否選擇更多的編譯環(huán)境,如果選YES,將會從第6步開使重復(fù)。如果選NO則會結(jié)束編譯器選擇。 12)接下來將會準(zhǔn)備產(chǎn)生一個 反映全局編譯信息顯示情況的選項(xiàng)文件OPTIONS.LNT,該文件的產(chǎn)生方式有兩種,一種是安裝程序?qū)讉核心選項(xiàng)逐一解釋并提問你是否取消該選項(xiàng),如果你選擇取消,則會體現(xiàn)在OPTIONS.LNT文件中,具體體現(xiàn)方式是在該類信息編碼前加-e,后面第13~18步是逐一選擇核心選項(xiàng)的過程。如果選擇第二種選擇方式,安裝文件會先生成一個空的OPTIONS.LNT文件,等你以后在實(shí)際應(yīng)用時(shí)加入必要的選項(xiàng)。 13)是否關(guān)閉賦值時(shí)的布爾測試告警,如:if(a=f()){... 14)是否關(guān)閉賦值時(shí)的有符號量和無符號量間的不匹配告警,通常情況下,這種賦值不會帶來問題,選擇關(guān)閉該告警信息的同時(shí),其他類型的有符號量和無符號量間混合操作的告警仍然是打開的。 15)當(dāng)把一個整形量賦值給一個比它短的量時(shí),后者會丟失精度,例如把一個INT量賦值給給一個CHAR量。本步是讓你選擇是否關(guān)閉該類告警。 16)是否關(guān)閉左移帶符號量的告警。通常PC-LINT會對所有帶符號量的移動產(chǎn)生告警,但右移一般是由不同的CPU來確定是否將符號位移入,左移一般是不會產(chǎn)生什么問題的,所以可以選擇關(guān)閉該告警。 17)在一個C函數(shù)被定義或聲明前調(diào)用它,并不總是會產(chǎn)生錯誤,在這里可以選擇是否關(guān)閉該告警選項(xiàng)。該選項(xiàng)對C++程序不起作用。 18)是否關(guān)閉“調(diào)用不存在的函數(shù)原型”告警。有些程序員不愿遵守嚴(yán)格的函數(shù)原形定義約定,但PC-LINT會在調(diào)用一個沒有定義的函數(shù)原型時(shí)產(chǎn)生一個告警,在這里可以選擇關(guān)閉該告警。 19)通過上面的步驟確定OPTIONS.LNT文件的形式后,接著是選擇編譯環(huán)境。PC-LINT提供了集成在多種開發(fā)環(huán)境中工作的功能,例如可集成在VC、BC、Source Insight中。假如我們在這里選擇Source Insight。選擇后安裝程序會繼續(xù)問你是否還選擇其它的環(huán)境,可根據(jù)自己應(yīng)用的實(shí)際情況選擇一種或多種開發(fā)環(huán)境。開發(fā)環(huán)境的選擇情況記錄在env-xxx.lnt文件中。 20)安裝程序會生成一個LIN.BAT文件,該文件是運(yùn)行PC-LINT的批處理文件,為了使該文件能在任何路徑下運(yùn)行,安裝程序提供了兩種方法供你選擇。第一種方法是讓你選擇把LIN.BAT拷貝到任何一個PATH目錄下,在安裝結(jié)束運(yùn)行LCOPY.BAT文件時(shí),會把LIN.BAT拷貝到你指定的目錄。第二種方法是生成一個LSET.BAT文件,在每次使用PC-LINT前先運(yùn)行它來設(shè)置路徑,或者把LSET.BAT文件的內(nèi)容拷貝到AUTOEXEC.BAT文件中。 21)在安裝程序執(zhí)行完后第一件事是在你安裝的目錄下執(zhí)行LCOPY.BAT文件。它會從安裝盤拷貝將一些文件拷貝到安裝目錄下,并根據(jù)你在安裝過程中的選擇來設(shè)置文件中的參數(shù)。 3.LINT 一個C文件 3.1用命令行方式進(jìn)行LINT 如果使用LIN.BAT批處理文件進(jìn)行LINT,在LINT前要先看一下該批處理文件中的內(nèi)容,里面包含了LINT-NT命令和命令選項(xiàng),可以根據(jù)自己的要求來修改、增減選項(xiàng)。我們看到,在這個批命令中嵌套了一個std.lnt文件,在std.lnt文件中還嵌套了co.lnt、options.lnt和lib-stl.lnt文件,原則上*.lnt文件是可以無限制嵌套,該類文件中一般都是了LINT的選項(xiàng),可通過修改這些文件來修改LINT選項(xiàng),選項(xiàng)是按照從左到右的順序執(zhí)行的?蓤(zhí)行下面命令行: C:\abc\src>lin alpha.c beta.c gamma.c 通常對于由多個C模塊組成的程序,最好先分別對每個C模塊單元進(jìn)行LINT檢查,做單元LINT時(shí)可如下運(yùn)行: C:\abs\src>lin -u alpha.c 其中-u是單元選項(xiàng),使用-u后可以關(guān)閉一些檢查多模塊時(shí)會產(chǎn)生的告警,例如“函數(shù)未被使用”或“函數(shù)沒有定義”等。 也可以不使用LIN.BAT批處理文件,而直接使用LINT命令。在DOS環(huán)境下LINT命令為LINT.EXE,在Windows95/NT環(huán)境下為LINT-NT.EXE,在OS2環(huán)境下為LINT-OS2.EXE。直接使用LINT命令要注意的一點(diǎn)是要在使用前預(yù)先設(shè)置LINT目錄所在路徑,最好的方法是把該路徑加在AUTOEXEC.BAT文件中。其它的使用方法與使用批處理文件相同。例如: C:\abs\src>lint-nt -ic:\lint\ std.lnt -os(_lint.tmp) *.c 3.2用開發(fā)環(huán)境進(jìn)行LINT 也可以使用開發(fā)環(huán)境來執(zhí)行LINT操作,一般開發(fā)環(huán)境都支持運(yùn)行可執(zhí)行文件,但不一定支持運(yùn)行批處理文件,下面用Source Insight , Ultra Edit, MSVC 6.0 來舉例說明如何在開發(fā)環(huán)境下進(jìn)行LINT。 3.2.1 在Source Insight中集成 如果你在安裝過程中選定了使用某個開發(fā)環(huán)境,安裝程序會在你安裝的目錄下生成一個env-xxx.lnt的文件,例如選擇了Source Insight就會有一個env-si.lnt文件。用編輯器打開該文件,在該文件開始的注釋中說明了如何將PC-LINT功能集成在開發(fā)環(huán)境中,集成在Source Insight中的過程如下: 1)從Options菜單中選擇“Custom Commands”命令項(xiàng)。 2)在Name欄中輸入“PC-lint ”,原則上這個名稱可以隨便起,只要你能搞清楚它的含義就可以了。 3)在Run欄中輸入“c:\lint\lint-nt -u -ic:\lint std env-si %f”其中c:\lint是你PC-LINT的安裝目錄。 4)在Output欄中選擇“Iconic Window”、“Capture Output”。 5)在Control欄中選擇“Save Files First”。 6)在Source Links in Output欄中選擇“Parse Links in Output”、“File,then Line”。 7)在Pattern欄中輸入“^\([^ ]*\) \([0-9]+\)”。 8)點(diǎn)Add鍵加入該命令。如下圖: 9)使用時(shí),在Source Insight下打開要LINT的文件,打開Options菜單中的“Custom Commands”命令項(xiàng),在“Command”欄中選擇“PC-lint unit check”命令運(yùn)行即可。 注意到我的Run一欄的參數(shù)和上面的提示不一樣,其實(shí)我的其他古怪參數(shù)都放到c:\lint\std.lnt中了。請注意,不論你怎樣配置參數(shù)一定不要忘記了將si-env.lnt包含在你的配置文件里,否則就無法進(jìn)行錯誤信息和程序的自動對應(yīng)了。 為了使用方便,你還可以配置一下Menu按鈕,將它加到系統(tǒng)菜0單里,這屬于一般性的 Source Insight應(yīng)用,筆者就不在此贅述了。 第二筆者在NT中使用Source Insight時(shí),好象集成不了,原因暫時(shí)不明了。上面的例子在WIN 95下測試成功。 如果要修改LINT選項(xiàng),可直接在Run欄中修改,也可專門編輯一個*.lnt文件放在c:\lint目錄下,并將該文件名加入Run欄中,和命令行方式是一樣的。 3.2.2在Ultra Editor中集成 選取 Menu | Advanced | Tool Configuration ... , 顯示如下圖: 1)點(diǎn)按“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)點(diǎn)按"OK" 如圖所示的配置筆者在UE6.0 / NT 4.0 下測試成功。 3.2.3 在MSVC 6.0中集成 基本原理是一樣的: 1)選取 menu | tools | customize..... 2)選取 Tools Tab: 3)點(diǎn)按主對話框上方的虛線小方框 New a tool item 4)輸入 name: PC-LINT 5)輸入 Command: c:\lint\lint-nt.exe 6)輸入 Arguments: c:\lint\std.lnt $(FilePath) 7) 選擇 (x) Use Output Window 8)Close 完成后,在tools菜單下就會有一項(xiàng)PC-LINT選項(xiàng)。 下面是筆者在VC6 / Win NT 4.0 的情況下的TOOL配置圖: 3.3LINT選項(xiàng) LINT選項(xiàng)可以放在注釋中,例如: /*lint option1 option2 ... optional commentary */ //lint option1 option2 ... optional commentary 選項(xiàng)間要以空格分開,lint命令一定要小寫,并且緊跟在/*或//后面,不能有空格。如果選項(xiàng)由類似于操作符和操作數(shù)的部分組成,例如-esym(534, printf, scanf, operat or new),其中最后一個選項(xiàng)是operator new,那么在operator和new中間只能有一個空 格。 選項(xiàng)還可以放在宏定義中,例如: #define DIVZERO(x) /*lint -save -e54 */ ((x) /o) /*lint -restore */ LINT的選項(xiàng)很多共有300多種,大體可分為以下幾類: 1)錯誤信息禁止選項(xiàng) 該類選項(xiàng)是用于禁止生成某類錯誤信息的選項(xiàng),最常用的是-e和+e,-e是禁止生成某類錯誤信息,+e是恢復(fù)生成某類錯誤信息。運(yùn)行l(wèi)int目錄下的msg.exe可以得到msg.txt文件,這個長達(dá)5000行的文件包含了所有的錯誤信息號和解釋。 -w 對于所有大于級別的告警信息都不顯示。 -wlib()對于所有大于級別的關(guān)于庫函數(shù)數(shù)的告警信息都不顯示。我們可以用-wlib(0)來屏蔽所有的庫函數(shù)的告警信息,-wlib(1)只顯示庫函數(shù)中的句法錯誤。 -esym(#,) 可以屏蔽對于特定符號的某告警信息。 2)變量類型大小選項(xiàng) 不同的目標(biāo)機(jī)、編譯系統(tǒng)變量類型的的大。ㄈ缍陶巫兞、整形變量等)會有所不同,該類選項(xiàng)用于為目標(biāo)機(jī)設(shè)置變量類型的大小。由于默認(rèn)的設(shè)置與大部分的編譯器是匹配的,這些專門的設(shè)置通常情況下是不需要的,只在特別的目標(biāo)機(jī)結(jié)構(gòu)中才用。例如一個M68000目標(biāo)機(jī),它的int類型和指針類型通常是32bit的,這時(shí)你應(yīng)該使用選項(xiàng):-si4 -sp4。這些尺寸參數(shù)的當(dāng)前值可以通過help屏來獲得,例如可以輸入以下命令行: lin -si4 -sp4 ? 3)冗長信息選項(xiàng) 冗長信息指的是LINT過程中產(chǎn)生的一些與編譯過程有關(guān)的信息,而不是真正的告警信息、錯誤信息等。是否生成這些信息可以通過-v和+v選項(xiàng)來決定。+v是生成這些信息,-v是關(guān)閉這些信息,這組選項(xiàng)中除+v外,其它所有選項(xiàng)都可以關(guān)閉+v選項(xiàng)。 4)標(biāo)記選項(xiàng) 以+f、++f、-f和--f開頭的選項(xiàng)是標(biāo)記選項(xiàng)。他們的邏輯含義分別如下: +f...:通過把標(biāo)志置為1而把它置為ON -f...:通過把標(biāo)志置為0而把它置為OFF ++f...:標(biāo)志增1 --f...:標(biāo)志減1 后面兩個用于你想在局部把一個標(biāo)志置為ON的情況,而不影響全局設(shè)置。例如你可以這樣使用: /*lint ++flb */ int printf( ); /*lint --flb */ 標(biāo)記選項(xiàng)的種類很多,基本含義是用于打開或關(guān)閉某類語法情況使用,例如允許使用縮寫結(jié)構(gòu)體名稱,允許使用無名聯(lián)合體,把所有模塊當(dāng)作C++編譯等。 5)消息顯示選項(xiàng) 消息顯示選項(xiàng)用于定義消息輸出格式。主要有消息高度選項(xiàng)、消息寬度選項(xiàng)、消息格式選項(xiàng)等。 6)其它選項(xiàng) 其它選項(xiàng)中的種類很多,各種類間差異很大,在這里就不一一介紹了,建議大家看一看《PC-LINT》一書,第五章有對每種選項(xiàng)的詳細(xì)說明。lint本身也有一些說明信息, lint-nt 2> lint.txt 然后狂按幾個回車就可以生成一個lint選項(xiàng)的說明文件。 4.LINT一個工程下的多個C文件 4.1為何要LINT多個C文件 在程序編碼初期,我們關(guān)心的可能只是單個C模塊種中的語法問題,等到編程后期,對于由多個C模塊組成的程序,我們希望了解當(dāng)把多個模塊連接在一起后是否還有存在于模塊間的語法問題。這時(shí)編譯器雖然能給出一些告警,但PC-LINT的連接能給出更多的告警。還有當(dāng)我們能保證其中的幾個模塊相對穩(wěn)定,而另外幾個模塊仍有問題時(shí)可以先將幾個穩(wěn)定的模塊編譯連接成一個目標(biāo)文件,文件每次修改完成后先單獨(dú)編譯,然后連接入總的目標(biāo)文件。 4.2如何LINT一個工程下的多個C文件 象我們平時(shí)使用的編譯工具一樣,PC-LINT在編譯連接多個C文件時(shí)也會先把每個C文件編譯生成中間的目標(biāo)文件*.lob,然后再將所有的LOB文件連接在一起。LOB是Lint Object Module的縮寫。這個文件中包含了一個C或C++模塊的所有外部信息。生成LOB文件時(shí)有三種選項(xiàng)要注意:第一種是-u,如果要LINT生成LOB文件,就一定要加-u選項(xiàng);第二種是-zero或-zero(500)選項(xiàng),為了保證LOB文件在模塊存在錯誤的情況下也能生成,就一定要加這個選項(xiàng);第三種是-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模塊,在用戶的源程序目錄下一般需要三個文件: 一個選項(xiàng)文件(*.lnt)、一個批處理文件(*.bat)和一個MAKEFILE文件(*.mak)。下面一一講述如何制作這些文件。 1)選項(xiàng)文件(*.lnt) 選項(xiàng)文件在前面也提到過,你可以把你LINT每個C文件時(shí)時(shí)用到的所有公共選項(xiàng)羅列在該文件中,選項(xiàng)生效的順序按照從左到右,從上到下的原則。該類文件可以層層嵌套,嵌套的層數(shù)沒有限制。例如make.lnt文件: -iC:\lint std.lnt +os(temp) -e46 +vm -zero 2)批處理文件(*.bat) 制作批處理文件時(shí)要注意要在該文件中調(diào)用TCMAKE.EXE文件和MAKEFILE文件,例如lintmake.mak文件: @echo Lint Making 'makelap': tcmake -flintmake.mak @echo End of making 3)MAKEFILE文件(*.mak) MAKEFILE使用的TCMAKE的語法,和我們平時(shí)開發(fā)編譯時(shí)使用的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多個文件 假設(shè)我們的工程不復(fù)雜,我們可以負(fù)擔(dān)起每次都將所有的文件都lint一遍的開銷,也可以不使用上面的正規(guī)用法。筆者在實(shí)踐中發(fā)現(xiàn),將所有的*.c文件放在一個lint命令中,同樣能完成lint整個工程的目的。 如: lint-nt c:\lint\std.lnt AllMySource.lnt 在AllMySource.lnt中包括你的工程中的所有源文件: a1.c a2.c a3.c 需要注意的是,在std.lnt文件中就不需要-u選項(xiàng)了。因?yàn)槲覀円呀?jīng)提供了所有的信息
|