大家可能一直在用VC開發軟體,但是對於這個編譯器卻未必很瞭解。原因是多方面的。大多數情況下,我們只停留在“使用”它,而不會想去“瞭解”它。因為它只是一個工具,我們寧可把更多的精力放在C++語言和軟體設計上。我們習慣於這樣一種“模式”:建立一個專案,然後寫程式碼,然後編譯,反反覆覆除錯。但是,所謂:“公欲善其事,必先利其器”。如果我們精於VC開發環境,我們是不是能夠做得更加遊刃有餘呢?
閒話少說。我們先來看一下VC的處理流程,大致分為兩步:編譯和連線。原始檔通過編譯生成了.obj檔案;所有.obj檔案和.lib檔案通過連線生成.exe檔案或.dll檔案。下面,我們分別討論這兩個步驟的一些細節。
一,編譯引數的設定。
主要通過VC的選單項Project->Settings->C/C++頁來完成。我們可以看到這一頁的最下面Project Options中的內容,一般如下:
/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_M
BCS" /Fp"Debug/WritingDlgTest.pch" /Yu"stdafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
各個引數代表的意義,可以參考Msdn。比如/nologo表示編譯時不在輸出視窗顯示這些設定(我們可以把這個引數去掉來看看效果)等等。一般我們不會直接修改這些設定,而是通過這一頁最上面的Category中的各項來完成。
1) General:一些總體設定。Warning level用來控制警告資訊,其中Level 1是最嚴重的級別;Warnings as errors將警告資訊當作錯誤處理;Optimizations是程式碼優化,可以在Category的Optimizations項中進行更細的設定;Generate browse info用以生成.sbr檔案,記錄類、變數等符號資訊,可以在Category的Listing Files項中進行更多的設定。Debug info,生成除錯資訊:None,不產生任何除錯資訊(編譯比較快);Line Numbers Only,僅生成全域性的和外部符號的除錯資訊到.OBJ檔案或.EXE檔案,減小目標檔案的尺寸;C 7.0- Compatible,記錄偵錯程式用到的所有符號資訊到.OBJ檔案和.EXE檔案;Program Database,建立.PDB檔案記錄所有除錯資訊;Program Database for "Edit & Continue",建立.PDB檔案記錄所有除錯資訊,並且支援除錯時編輯。
2) C++ Language:pointer_to_member representation用來設定類定義/引用的先後關係,一般為Best-Case Always表示在引用類之前該類肯定已經定義了;Enable Exception Handling,進行同步的異常處理;Enable Run-Time Type Information迫使編譯器增加程式碼在執行時進行物件型別檢查;Disable Construction Displacements,設定類構造/解構函式呼叫虛擬函式問題。
3) Code Generation:Processor表示程式碼指令優化,可以為80386、80486、Pentium、Pentium Pro,或者Blend表示混合以上各種優化。Use run-time library用以指定程式執行時使用的執行時庫(單執行緒或多執行緒,Debug版本或Release版本),有一個原則就是,一個程式不要同時使用幾個版本的執行時庫。Single-Threaded,靜態連線LIBC.LIB庫;Debug Single-Threaded,靜態連線LIBCD.LIB庫;Multithreaded,靜態連線LIBCMT.LIB庫;Debug Multithreaded,靜態連線LIBCMTD.LIB庫;Multithreaded DLL,動態連線MSVCRT.DLL庫;Debug Multithreaded DLL,動態連線MSVCRTD.DLL庫。連線了單執行緒庫就不支援多執行緒呼叫,連線了多執行緒庫就要求建立多執行緒的應用程式。
Calling convention可以用來設定呼叫約定,有三種:__cdecl、__fastcall和__stdcall。各種呼叫約定的主要區別在於,函式呼叫時,函式的引數是從左到右壓入堆疊還是從右到左壓入堆疊;在函式返回時,由函式的呼叫者來清理壓入堆疊的引數還是由函式本身來清理;以及在編譯時對函式名進行的命名修飾(可以通過Listing Files看到各種命名修飾方式)。Struct member alignment用以指定資料結構中的成員變數在記憶體中是按幾位元組對齊的,根據計算機資料匯流排的位數,不同的對齊方式存取資料的速度不一樣。這個引數對資料包網路傳輸等應用尤為重要,不是存取速度問題,而是資料位的精確定義問題,一般在程式中使用#pragma pack來指定。
4) Customize:Disable Language Extensions,表示不使用微軟為標準C做的語言擴充套件;Eliminate Duplicate Strings,主要用於字串優化(將字串放到緩充池裡以節省空間),使用這個引數,使得
char *sBuffer = "This is a character buffer"; char *tBuffer = "This is a character buffer"; |
sBuffer和tBuffer指向的是同一塊記憶體空間;Enable Function-Level Linking ,告訴編譯器將各個函式按打包格式編譯;Enables minimal rebuild,通過儲存關聯資訊到.IDB檔案,使編譯器只對最新類定義改動過的原始檔進行重編譯,提高編譯速度;Enable Incremental Compilation,同樣通過.IDB檔案儲存的資訊,只重編譯最新改動過的函式;Suppress Startup Banner and Information Messages,用以控制引數是否在output視窗輸出。
5) Listing Files:Generate browse info的功能上面已經提到過。這裡可以進行更多的設定。Exclude Local Variables from Browse Info表示是否將區域性變數的資訊放到.SBR檔案中。Listing file type可以設定生成的列表資訊檔案的內容:Assembly-Only Listing僅生成彙編程式碼檔案(.ASM副檔名);Assembly With Machine Code生成機器程式碼和彙編程式碼檔案(.COD副檔名);Assembly With Source Code生成原始碼和彙編程式碼檔案(.ASM副檔名);Assembly, Machine Code,and Source生成機器碼、原始碼和彙編程式碼檔案(.COD副檔名)。Listing file name為生成的資訊檔案的路徑,一般為Debug或Release目錄下,生成的檔名自動取原始檔的檔名。
6) Optimizations:程式碼優化設定。可以選擇Maximize Speed生成最快速的程式碼,或Minimize Size生成最小尺寸的程式,或者Customize定製優化。定製的內容包括:
Assume No Aliasing,不使用別名(提高速度);
Assume Aliasing Across Function Calls,僅函式內部不使用別名;
Global Optimizations,全域性優化,比如經常用到的變數使用暫存器儲存,或者迴圈內的計算優化,如
i = -100; while( i < 0 ){ i += x + y;} |
會被優化為
i = -100; t = x + y; while( i < 0 ){i += t;} Generate Intrinsic Functions,使用內部函式替換一些函式呼叫(提高速度); Improve Float Consistency,浮點運算方面的優化; Favor Small Code,程式(exe或dll)尺寸優化優先於程式碼速度優化; Favor Fast Code,程式(exe或dll)程式碼速度優化優先於尺寸優化; Frame-Pointer Omission,不使用幀指標,以提高函式呼叫速度; Full Optimization,組合了幾種引數,以生成最快的程式程式碼。 |
Inline function expansion,行內函數擴充套件的三種優化(使用內聯可以節省函式呼叫的開銷,加快程式速度):Disable不使用內聯;Only __inline,僅函式定義前有inline或__inline標記使用內聯;Any Suitable,除了inline或__inline標記的函式外,編譯器“覺得”應該使用內聯的函式,都使用內聯。
7) Precompiled Headers:預編譯標頭檔案的設定。使用預編譯可以提高重複編譯的速度。VC一般將一些公共的、不大變動的標頭檔案(比如afxwin.h等)集中放到stdafx.h中,這一部分程式碼就不必每次都重新編譯(除非是Rebuild All)。
8) Preprocessor:預編譯處理。可以定義/解除定義一些常量。Additional include directories,可以指定額外的包含目錄,一般是相對於本專案的目錄,如..\Include。
二,連線引數的設定。
主要通過VC的選單項Project->Settings->Link頁來完成。我們可以看到這一頁的最下面Project Options中的內容,一般如下:
/nologo /subsystem:windows /incremental:yes /pdb:"Debug/WritingDlgTest.pdb" /debug /machi
ne:I386 /out:"Debug/WritingDlgTest.exe" /pdbtype:sept
下面我們分別來看一下Category中的各項設定。
1) General:一些總體設定。可以設定生成的檔案路徑、檔名;連線的庫檔案;Generate debug info,生成Debug資訊到.PDB檔案(具體格式可以在Category->Debug中設定);Ignore All Default Libraries,放棄所有預設的庫連線;Link Incrementally,通過生成. ILK檔案實現遞增式連線以提高後續連線速度,但一般這種方式下生成的檔案(EXE或DLL)較大;Generate Mapfile,生成.MAP檔案記錄模組相關資訊;Enable Profiling,這個引數通常與Generate Mapfile引數同時使用,而且如果產生Debug資訊的話,不能用.PDB檔案,而且必須用Microsoft Format。
2) Customize:這裡可以進行使用程式資料庫檔案的設定。Force File Output ,強制產生輸出檔案(EXE或DLL);Print Progress Messages,可以將連線過程中的進度資訊輸出到Output視窗。
3) Debug:設定是否生成除錯資訊,以及除錯資訊的格式。格式可以有Microsoft Format、COFF Format(Common Object File Format)和Both Formats三種選擇;Separate Types,表示將Debug格式資訊以獨立的.PDB檔案存放,還是直接放在各個原始檔的.PDB檔案中。選中的話,表示採用後者的方式,這種方式除錯啟動比較快。
4) Input:這裡可以指定要連線的庫檔案,放棄連線的庫檔案。還可以增加額外的庫檔案目錄,一般是相對於本專案的目錄,如..\Lib。Force Symbol References,可以指定連線特定符號定義的庫。
5) Output:Base Address可以改變程式預設的基地址(EXE檔案預設為0x400000,DLL預設為x10000000),作業系統裝載一個程式時總是試著先從這個基地址開始。Entry-Point Symbol可以指定程式的入口地址,一般為一個函式名(且必須採用__stdcall呼叫約定)。一般Win32的程式,EXE的入口為WinMain,DLL的入口為DllEntryPoint;最好讓聯結器自動設定程式的入口點。預設情況下,通過一個C的執行時庫函式來實現:控制檯程式採用mainCRTStartup (或wmainCRTStartup)去呼叫程式的main (或wmain)函式;Windows程式採用WinMainCRTStartup (或 wWinMainCRTStartup)呼叫程式的WinMain (或 wWinMain,必須採用__stdcall呼叫約定);DLL採用_DllMainCRTStartup呼叫DllMain函式(必須採用__stdcall呼叫約定)。Stack allocations,用以設定程式使用的堆疊大小(請使用十進位制),預設為1兆位元組。Version Information告訴聯結器在EXE或DLL檔案的開始部分放上版本號。
值得注意的是,上面各個引數是大小寫敏感的;在引數後加上“-”表示該引數無效;各個引數值選項
有“*”的表示為該引數的預設值;可以使用頁右上角的“Reset”按鈕來恢復該頁的所有預設設定。
三,其它一些引數設定
1) Project->Settings->General,可以設定連線MFC庫的方式(靜態或動態)。如果是動態連
接,在你的軟體釋出時不要忘了帶上MFC的DLL。
2) Project->Settings->Debug,可以設定除錯時執行的可執行檔案,以及命令列引數等。
3) Project->Settings->Custom Build,可以設定編譯/連線成功後自動執行一些操作。比較有
用的是,寫COM時希望VC對編譯通過的COM檔案自動註冊,可以如下設定:
Description: Register COM
Commands: regsvr32 /s /c $(TargetPath)
echo regsvr32 exe.time > $(TargetDir)\$(TargetName).trg
Outputs: $(TargetDir)\$(TargetName).trg
4) Tools->Options->Directories,設定系統的Include、Library路徑。
一些小竅門
1) 有時候,你可能在編譯的時候,計算機突然非法關機了(可能某人不小心碰了電源或你的記憶體不穩定等原因)。當你重啟機器後開啟剛才的專案,重新進行編譯,發現VC會崩掉。你或許以為你的VC編譯器壞了,其實不然(你試試編譯其它專案,還是好的!),你只要將專案的.ncb、.opt、.aps、.clw檔案以及Debug、Release目錄下的所有檔案都刪掉,然後重新編譯就行
了。
2) 如果你想與別人共享你的原始碼專案,但是把整個專案做拷貝又太大。你完全可以刪掉以下檔案:.dsw、.ncb、.opt、.aps、.clw、. plg檔案以及Debug、Release目錄下的所有檔案。
3) 當你的Workspace中包含多個Project的時候,你可能不能直觀地、一眼看出來哪個是當前專案。可以如下設定:Tools->Options->Format,然後在Category中選擇Workspace window,改變其預設的字型(比如設成Fixedsys)就行了。
4) 如何給已有的Project改名字?將該Project關掉。然後以文字格式開啟.dsp檔案,替換原來的Project名字即可。
5) VC6對類成員的智慧提示功能很有用,但有時候會失靈。你可以先關掉專案,將.clw和.ncb刪掉,然後重新開啟專案,點選選單項View->ClassWizard,在彈出的對話方塊中按一下“Add All”按鈕;重新Rebuild All。應該可以解決問題。
VC編譯選項
-優化-
/O1 最小化空間 minimize space
/Op[-] 改善浮點數一致性 improve floating-pt consistency
/O2 最大化速度 maximize speed
/Os 優選程式碼空間 favor code space
/Oa 假設沒有別名 assume no aliasing
/Ot 優選程式碼速度 favor code speed
/Ob 內聯展開(預設 n=0) inline expansion (default n=0)
/Ow 假設交叉函式別名 assume cross-function aliasing
/Od 禁用優化(預設值) disable optimizations (default)
/Ox 最大化選項。(/Ogityb2 /Gs) maximum opts. (/Ogityb1 /Gs)
/Og 啟用全域性優化 enable global optimization
/Oy[-] 啟用框架指標省略 enable frame pointer omission
/Oi 啟用內建函式 enable intrinsic functions
-程式碼生成-
/G3 為 80386 進行優化 optimize for 80386
/G4 為 80486 進行優化 optimize for 80486
/GR[-] 啟用 C++ RTTI enable C++ RTTI
/G5 為 Pentium 進行優化 optimize for Pentium
/G6 為 Pentium Pro 進行優化 optimize for Pentium Pro
/GX[-] 啟用 C++ 異常處理(與 /EHsc 相同) enable C++ EH (same as /EHsc)
/EHs 啟用同步 C++ 異常處理 enable synchronous C++ EH
/GD 為 Windows DLL 進行優化 optimize for Windows DLL
/GB 為混合模型進行優化(預設) optimize for blended model (default)
/EHa 啟用非同步 C++ 異常處理 enable asynchronous C++ EH
/Gd __cdecl 呼叫約定 __cdecl calling convention
/EHc extern“C”預設為 nothrow extern "C" defaults to nothrow
/Gr __fastcall 呼叫約定 __fastcall calling convention
/Gi[-] 啟用增量編譯 enable incremental compilation
/Gz __stdcall 呼叫約定 __stdcall calling convention
/Gm[-] 啟用最小重新生成 enable minimal rebuild
/GA 為 Windows 應用程式進行優化 optimize for Windows Application
/Gf 啟用字串池 enable string pooling
/QIfdiv[-] 啟用 Pentium FDIV 修復 enable Pentium FDIV fix
/GF 啟用只讀字串池 enable read-only string pooling
/QI0f[-] 啟用 Pentium 0x0f 修復 enable Pentium 0x0f fix
/Gy 分隔連結器函式 separate functions for linker
/GZ 啟用執行時除錯檢查 enable runtime debug checks
/Gh 啟用鉤子函式呼叫 enable hook function call
/Ge 對所有函式強制堆疊檢查 force stack checking for all funcs
/Gs[num] 禁用堆疊檢查呼叫 disable stack checking calls
-輸出檔案-
/Fa[file] 命名程式集列表檔案 name assembly listing file
/Fo 命名物件檔案 name object file
/FA[sc] 配置程式集列表 configure assembly listing
/Fp 命名預編譯標頭檔案 name precompiled header file
/Fd[file] 命名 .PDB 檔案 name .PDB file
/Fr[file] 命名源瀏覽器檔案 name source browser file
/Fe 命名可執行檔案 name executable file
/FR[file] 命名擴充套件 .SBR 檔案 name extended .SBR file
/Fm[file] 命名對映檔案 name map file
-前處理器-
/FI 命名強制包含檔案 name forced include file
/C 不吸取註釋 don't strip comments
/U 移除預定義巨集 remove predefined macro
/D{=|#} 定義巨集 define macro
/u 移除所有預定義巨集 remove all predefined macros
/E 將預處理定向到標準輸出 preprocess to stdout
/I 新增到包含檔案的搜尋路徑 add to include search path
/EP 將預處理定向到標準輸出,不要帶行號 preprocess to stdout, no #line
/X 忽略“標準位置” ignore "standard places"
/P 預處理到檔案 preprocess to file
-語言-
/Zi 啟用除錯資訊 enable debugging information
/Zl 忽略 .OBJ 中的預設庫名 omit default library name in .OBJ
/ZI 啟用除錯資訊的“編輯並繼續”功能 enable Edit and Continue debug info
/Zg 生成函式原型 generate function prototypes
/Z7 啟用舊式除錯資訊 enable old-style debug info
/Zs 只進行語法檢查 syntax check only
/Zd 僅要行號除錯資訊 line number debugging info only
/vd{0|1} 禁用/啟用 vtordisp disable/enable vtordisp
/Zp[n] 在 n 位元組邊界上包裝結構 pack structs on n-byte boundary
/vm 指向成員的指標型別 type of pointers to members
/Za 禁用擴充套件(暗指 /Op) disable extensions (implies /Op)
/noBool 禁用“bool”關鍵字 disable "bool" keyword
/Ze 啟用擴充套件(預設) enable extensions (default)
- 雜項 -
/?, /help 列印此幫助訊息 print this help message
/c 只編譯,不連結 compile only, no link
/W 設定警告等級(預設 n=1) set warning level (default n=1)
/H 最大化外部名稱長度 max external name length
/J 預設 char 型別是 unsigned default char type is unsigned
/nologo 取消顯示版權訊息 suppress copyright message
/WX 將警告視為錯誤 treat warnings as errors
/Tc 將檔案編譯為 .c compile file as .c
/Yc[file] 建立 .PCH 檔案 create .PCH file
/Tp 將檔案編譯為 .cpp compile file as .cpp
/Yd 將除錯資訊放在每個 .OBJ 中 put debug info in every .OBJ
/TC 將所有檔案編譯為 .c compile all files as .c
/TP 將所有檔案編譯為 .cpp compile all files as .cpp
/Yu[file] 使用 .PCH 檔案 use .PCH file
/V 設定版本字串 set version string
/YX[file] 自動的 .PCH 檔案 automatic .PCH
/w 禁用所有警告 disable all warnings
/Zm 最大記憶體分配(預設為 %) max memory alloc (% of default)
-連結-
/MD 與 MSVCRT.LIB 連結 link with MSVCRT.LIB
/MDd 與 MSVCRTD.LIB 除錯庫連結 link with MSVCRTD.LIB debug lib
/ML 與 LIBC.LIB 連結 link with LIBC.LIB
/MLd 與 LIBCD.LIB 除錯庫連結 link with LIBCD.LIB debug lib
/MT 與 LIBCMT.LIB 連結 link with LIBCMT.LIB
/MTd 與 LIBCMTD.LIB 除錯庫連結 link with LIBCMTD.LIB debug lib
/LD 建立 .DLL Create .DLL
/F 設定堆疊大小 set stack size
/LDd 建立 .DLL 除錯庫 Create .DLL debug libary
/link [連結器選項和庫] [linker options and libraries]