目錄
第1章編譯步驟
使用Visual C++ 6.0新建一個MFC程序,然后編譯。IDE(集成開發環境)下,可以看到編譯信息:

圖1.1 VC++6.0編譯信息
可見其編譯的基本步驟為:
1、刪除項目的臨時文件和輸出文件;
2、編譯資源,即編譯rc文件,生成res文件;
3、預編譯頭文件,生成pch文件;
4、編譯各個源文件(*.c、*.cpp、*.cxx),生成obj文件;
5、鏈接。具體的就是將obj、res文件合成為一個exe文件,中間可能還需要一些Lib文件。
注意:EVC3.0和EVC4.0的編譯步驟與VC++6.0完全一致。VC++6.0之后的版本,其編譯步驟發生了變化。第2步的編譯資源被移至第4步之后。
從上面的編譯步驟可以看到,編譯時並沒有編譯頭文件(*.h)。這樣是否就意味着不需要頭文件了?答案當然是否定的。事實上在編譯源文件時,預編譯器首先處理#include指令,它會將頭文件包含至源文件后再進行編譯。編譯器是以這種方式使用頭文件的,認識到這一點對於理解C/C++編譯至關重要。
第2章編譯源文件
VC++6.0里編譯就是調用C:\Program Files\Microsoft Visual Studio\VC98\Bin\cl.exe將源文件(*.c、*.cpp、*.cxx)編譯為obj文件。
2.1 編譯器
假定1.cpp里有如下代碼:
| int a = 0; ++a; int b = a + 1; |
顯然編譯它是沒問題的,但是把1.cpp改名為1.c,再次編譯就會出問題。為什么?原因很簡單:源文件的擴展名為c時,編譯器按C語言的語法進行編譯,生成C代碼;源文件的擴展名為cpp或cxx時,編譯器按C++語言的語法進行編譯,生成C++代碼。C和C++語法還是有一定差別的。
大家都知道C++支持函數重載,如下面兩個函數在C++里是允許的:
| int fun(); int fun(int a); |
但在C語言里是不允許的。為什么呢?因為C語言編譯fun時不會將其更名,一個obj文件里是不能有兩個同名函數的。C++語言就不同了,會將這兩個函數自動更名。VC++6.0里將fun()更名為?fun@@YAHXZ,將fun(int a)更名為?fun@@YAHH@Z,程序員眼里的一個函數fun在編譯器眼里仍是兩個。
這樣就引來一個問題:如果一個函數funA在.c文件里,而程序在.cpp里調用了funA函數會出現什么情況?答案是無法調用:因為funA在obj里的名字就是funA,但cpp要連接的funA已經被更名了。為了在cpp里調用c函數,函數聲明時需要使用extern "C"語句。如下面代碼。
| extern "C" int fun(); extern "C" { int funcA(); int funcB(); } |
在C和C++混合編程的時候一定要注意這個問題。
2.2 包含頭文件
編譯源文件時,若遇到 #include "A.h" 語句,則編譯器對頭文件的搜索順序如下:
1、#include語句所在文件的目錄
如:C:\VC\1.c 里有 #include "A.h",則編譯器會在1.c所在目錄查找A.h,即在C:\VC下查找A.h;
如:C:\VC\1.c 里有 #include "../B.h",則編譯器會在1.c所在目錄查找../B.h,就是查找C:\VC\..\B.h,即C:\B.h。這里的..表示相對路徑,即上一級目錄。#include "../B.h"里的斜杠/可以換成反斜杠\,不過因為在雙引號里\表示轉義字符,所以需要兩個反斜杠,即:#include "..\\B.h"。以一個斜杠代替兩個反斜杠完全是為了簡化;
說明:相對路徑可通過vcHelper程序獲取,這樣較為方便。
2、上一級包含文件所在目錄
如:C:\VC\1.c 里有 #include "A.h"。編譯器在D:\Test目錄下找到了A.h。這個A.h里又有#include "B.h",顯然編譯器會首先在A.h所在目錄D:\Test下查找B.h,如果找不到則會在C:\VC\1.c所在目錄繼續查找。
3、Additional include directories 所列目錄下依次進行查找
Additional include directories的設置僅對本項目有效,具體請參考圖2.1或圖2.2。VC++6.0的多個路徑之間請以逗號分隔。路徑可以使用絕對路徑也可以使用相對路徑。如:C:/VC,../Share,./Inc表示了三個目錄:
C:\VC 絕對路徑
..\Share 相對於項目文件(dsp、vcp、vcproj)的相對路徑
.\Inc 相對於項目文件(dsp、vcp、vcproj)的相對路徑
搜索頭文件時,先搜索C:\VC目錄,再搜索..\Share目錄,最后搜索.\Inc目錄。

圖2.1 VC++6.0 的Additional include directories

圖2.2 VC++7.0 的Additional include directories
4、在Standard Include Paths里依次進行查找
Standard Include Paths的設置對所有VC++項目都有效。
VC++6.0下,單擊【Tools】菜單下的【Option】菜單項,然后進入Directories頁面,如下圖所示。

圖2.3 VC++6.0 的Standard Include Paths
VC++7.0下,單擊【Tools】菜單下的【Option】菜單項。顯示界面如下圖所示。

圖2.4 VC++7.0 的Standard Include Paths
以上討論的是#include ""語句,如果是 #include <>,則對頭文件的查找順序將是上面的第 3、4步。
建議:
1、如果是自己寫的頭文件,請使用#include ""語句,並使用相對路徑;
2、如果是系統的頭文件,如:stdio.h,請使用#include <>語句。
2.3 重復包含
假如1.cpp里包含了頭文件A.h和B.h,這兩個頭文件又都包含了C.h。顯然編譯1.cpp時,C.h將被包含兩次。C.h里的結構、類定義也會出現兩次,編譯器會認為這些結構、類被重復定義了,從而導致編譯失敗。
解決辦法有兩個
1、增加#ifndef ... #define ... #endif
如:在C.h里增加如下代碼:
| //C.h #ifndef __C_H__ #define __C_H__ //以下是C.h的文件內容 ... ... ... //最后別忘了#endif #endif //__C_H__ |
編譯器編譯1.cpp,第二次包含C.h的時候,因為__C_H__已經被定義了,因此會舍棄第二次包含的內容。
該方法要保證每個頭文件里的__C_H__都不相同,否則會導致某兩個頭文件不能同時被包含。
2、增加#pragma once語句
這個方法比較簡單,直接在C.h里增加#pragma once即可。美中不足的是:並不是所有的編譯器都支持這條指令。所以,采用其它C/C++編譯器的時候要注意這一點。
2.4 預編譯頭文件
假如有多個源文件都包含了windows.h文件。這個頭文件非常大,每次編譯都比較耗時。有幾個源文件包含了它,它就要被編譯幾次。顯然這樣的編譯效率是相當低的。能不能只編譯一次這樣的頭文件?答案是肯定,那就是使用預編譯頭文件。即在編譯源文件之前,先把windows.h編譯出來生成pch文件。在編譯源文件的時候,編譯器遇到windows.h時將不再編譯,而是直接使用pch文件。這個pch就是預編譯頭文件。
2.4.1 創建
正如前面所說的,編譯器是不會直接編譯頭文件的。因此要預編譯頭文件,需要指定一個源文件來完成編譯並生成pch文件。這里假定要預編譯windows.h。請創建一個源文件,如:pch.cpp。其內容很簡單,就是#include <windows.h>。然后設置pch.cpp的屬性,使其創建pch文件。VC++6.0的設置界面如下:

圖2.5 VC++6.0創建預編譯頭文件設置
在VC++7.0的Solution Explorer里,右鍵單擊pch.cpp,然后單擊【Properties】菜單項,設置界面如下圖所示

圖2.6 VC++7.0創建預編譯頭文件設置
2.4.2 使用
創建PCH文件后,需要設置其它的源文件使用它。
VC++6.0的設置界面如下。

圖2.7 VC++6.0使用預編譯頭文件設置
在VC++7.0的Solution Explorer里,選擇要使用預編譯頭文件的源文件,然后右鍵單擊某一選中文件,或直接右鍵單擊項目然后單擊【Properties】菜單項,設置界面如下圖所示。注意下圖里的my.pch要和圖2.6的保持一致,即:創建什么pch文件就使用什么pch文件。

圖2.8 VC++7.0使用預編譯頭文件設置
設置多個源文件的屬性與設置項目屬性的區別:項目就好像國家,源文件就好像各個省。國家出台了政策后,各個省要遵循;但是各個省可以根據自己的情況對政策進行修改。一個源文件的某個屬性沒有進行設置,則它使用項目的該屬性。項目的屬性改變后,這個源文件的屬性也隨之改變。但是如果單獨對這個源文件的屬性進行了設置,則項目屬性的改變對它沒有影響。
2.4.3 說明
需要說明以下幾點:
1、VC++7.0項目里可以使用多個預編譯頭文件;VC++6.0項目使用多個預編譯頭文件好像比較困難;
2、創建MFC程序后,預編譯頭文件設置已經完成,一般無需再設置;
3、一個源文件一旦使用了預編譯頭文件A.h,則該源文件的第一行一定要包含該頭文件。換句話說#include "A.h"之前的代碼將被忽略;
4、編譯預編譯頭文件出錯后,很難調試。因為不知道編譯到哪一行出錯了?解決方法就是使用#error或#pragma message跟蹤編譯進度,精確定位編譯出錯的位置。
第3章編譯資源
Windows程序需要資源,如:圖標、光標、對話框……VC++6.0里編譯資源就是調用C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe將資源文件(*.rc)編譯為res文件。連接程序負責將res文件嵌入exe文件。
3.1 編譯
使用記事本創建資源文件1.rc,其內容如下所示。只有一個 ID 為 100 的字符串。注意:1.rc的編碼必須為ANSI。
| STRINGTABLE DISCARDABLE { 100 "This is a string" } |
在DOS命令窗口,執行如下命令
| "C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" C:\1.rc |
rc.exe將編譯1.rc,並生成1.res。可以使用VC++6.0打開1.res,查看資源內容。
3.1.1 輸出文件
默認情況下,1.res與1.rc在同一目錄。可以通過/fo命令開關更改輸出文件,如下命令將更改輸出文件為D:\t.res。
| "C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" /fo"D:\t.res" C:\1.rc |
在集成開發環境下,Resource file name 對應的就是/fo命令開關。集成開發環境編譯時,會將dsp、vcproj文件所在目錄設置為當前目錄,所以如果Resource file name不是絕對路徑,那么它就是相對dsp文件目錄的相對路徑。

圖3.1 VC++6.0資源設置

圖3.2 VC++7.0資源設置
3.1.2 語言
將1.rc文件修改成如下內容:
| STRINGTABLE DISCARDABLE { 100 "這是一個字符串" } |
使用VC++6.0打開編譯生成的res文件,會發現字符串是亂碼。因為rc.exe默認使用的語言是美國英語,語言ID為0x409。需要將語言ID更改為簡體中文的0x804。具體命令如下:
| "C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" /fo"D:\t.res" /l804 C:\1.rc |
命令開關/l804相當於在1.rc的第一行插入如下語句:
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
即明確指定語言為簡體中文。
如果1.rc的第一行為 LANGUAGE 9,1。即已經指定語言為美國英語,則命令開關/l804是不起任何作用的。
在集成開發環境下,可以通過修改"Language"或"Culture"修改/l命令開關。
3.2 include語句
假定資源文件1.rc里有語句#include "1.rc2",而1.rc2里又有語句#include "2.rc2"。按如下命令進行編譯:

圖3.3 編譯資源
則查找2.rc2的順序如下:
1、包含它的文件(1.rc2)所在目錄;
2、1.rc2被1.rc包含,所以如果上一步未找到,繼續在1.rc所在目錄查找;
3、在當前目錄查找。上圖中,當前目錄就是C:\User\yhf;
4、由命令開關/i指定的目錄。上圖中,有兩項/i。會依次在D:\inc1、D:\inc2中查找。集成開發環境中,可以設定這些目錄。
5、如果在集成環境編譯,還會在設置的Include目錄中查找。至於它的實現,筆者猜測:集成開發環境調用rc.exe時,將Include目錄添加至/i命令開關。
3.3 引用文件
有些資源,如圖標,其實就是引用的圖標文件,如下面的語句:
| IDR_MAINFRAME ICON DISCARDABLE "res\\t6.ico" |
假如上面一行語句位於2.rc2,那么查找res\t6.ico的順序如下:
1、被編譯資源文件所在目錄。注意:rc.exe不會查找2.rc2和1.rc2所在目錄,它會認為這條語句位於被編譯的資源文件(1.rc)內。
2、當前目錄;
3、由命令開關/i指定的目錄。上圖中,有兩項/i。會依次在D:\inc1、D:\inc2中查找。集成開發環境中,可以設定這些目錄。
4、如果在集成環境編譯,還會在設置的Include目錄中查找。
第4章連接
VC++6.0里連接就是調用C:\Program Files\Microsoft Visual Studio\VC98\Bin\link.exe將編譯生成的obj、res合成為一個exe文件或dll文件。
連接的時候可能還需要其他程序員生成的obj文件和lib文件,使用這些文件的方法有三種。
1、增加該文件至VC項目

圖4.1 增加文件至項目
該方法的優點就是簡單,缺點是不靈活。如這個方法很難處理這個要求:對於Debug版本需要連接TestD.lib,對於Release版需要連接Test.lib。
2、修改項目設置
首先增加文件,如圖4.2和圖4.3所示。
如果需要,還可以指定 Additional library path。如圖4.2和圖4.4所示。VC++6.0連接程序時,首先在項目目錄(即dsp、vcp、vcproj文件所在目錄)下查找 Func.obj 和 Test.lib,其次在Additional library path下查找,最后在標准目錄下查找。標准庫文件目錄的設置請參考圖2.3和圖2.4。

圖4.2 VC++6.0增加庫文件及設置庫文件目錄

圖4.3 VC++7.0增加庫文件

圖4.4 VC++7.0設置庫文件目錄
3、在頭文件或源文件中,插入如下代碼:
#pragma comment(lib, "Test.lib") //連接時使用 Test.lib。
接着指定 Additional library path,請參考方法2里的描述。連接器查找 Test.lib 時,其查找順序與第 2 種方法相同。
這種方法非常靈活,請見下面的代碼。其含義為:Debug版本下連接TestD.lib,Release版本下連接Test.lib。
| #ifdef _DEBUG #pragma comment(lib, "TestD.lib") #else #pragma comment(lib, "Test.lib") #endif |
說明:
1、這種方法不能指定obj文件;
2、#pragma comment還可指定絕對路徑和相對路徑,但是建議不要這樣做。
第5章其它
5.1 編譯目錄
編譯、連接的時候會產生大量的文件,可以指定這些文件的存放路徑。
臨時目錄用來存放編譯過程中產生的文件,如:pch、obj、res文件。輸出目錄用來存放最終生成的exe或dll文件。這兩個目錄的設置如下圖所示。注意它們可以是絕對路徑,也可以是相對於dsp、vcp、vcproj文件的相對路徑。

圖5.1 VC++6.0臨時、輸出目錄設置

圖5.2 VC++7.0臨時、輸出目錄設置
建議將臨時、輸出目錄設置為Temp,便於查找、刪除這些文件。
還可以指定目標文件,請參考下圖。

圖5.3 VC++6.0設置目標文件

圖5.4 VC++7.0設置目標文件
5.2 編譯事件
編譯的時候有三個事件:
1、Pre-Build
開始編譯、連接的時候發生該事件。VC++7.0以上的版本才支持此事件。
2、Pre-Link
編譯完畢,准備連接的時候發生該事件。
3、Post-Build
編譯、連接都結束的時候發生該事件。
假如需要在程序編譯完成的時候將exe文件移動到c:\,可在Post-Build里增加DOS命令:move $(TargetPath) c:\。具體的設置請參考下圖。

圖5.5 VC++6.0增加編譯后處理命令

圖5.6 VC++7.0增加編譯后處理命令
$(TargetPath)是編譯時產生的環境變量,其它的環境變量及含義見下表
| 環境變量 |
說明 |
| $(MSDEVDIR) |
Microsoft Developer目錄,如:C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98 |
| $(IntDir) |
臨時目錄 |
| $(OutDir) |
輸出目錄 |
| $(TargetPath) |
目標文件,包括路徑 |
| $(TargetDir) |
目標文件所在目錄 |
| $(TargetName) |
目標文件名,不包括路徑和擴展名 |
5.3 自定義編譯
有沒有想過在VC++6.0里編譯VC#代碼?有了Custom Build一切皆有可能。假定有如下VC#代碼,存在於文件1.cs。
| using System; using System.Windows.Forms; static class Program { static void Main() { MessageBox.Show("Hello VC#"); } } |
請將1.cs添加至VC++6.0工程,並設置其Custom Build屬性:

Commands有兩條命令,第一行為:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe /out:$(InputDir)\$(InputName).exe $(InputPath)
其實就是調用csc程序,編譯1.cs文件,生成1.exe文件。環境變量$(InputPath)就是1.cs相對於dsp文件的路徑(包括文件名)。環境變量$(InputDir)是$(InputPath)的目錄部分。環境變量$(InputName)是1.cs的文件名,不包括擴展名,其實就是1了。$(InputDir)\$(InputName).exe其實就是與1.cs在同一目錄下的文件1.exe。
第二行命令為$(InputDir)\$(InputName).exe,其實就是編譯結束后運行這個程序。
Outputs里為輸出文件,這里就是$(InputDir)\$(InputName).exe了。
編譯后,可以看到運行結果。

圖5.7 編譯VC#
可以猜測到Custom Build的編譯步驟:
1、刪除輸出文件,這里就是1.exe;
2、設置當前目錄為dsp所在目錄;
3、設置環境變量;
4、調用Commands里面的命令。命令的輸出全部被重定向至VC++6.0的Output窗口,這樣就可以在IDE里查看編譯結果。
5.4 預定義宏
對於VC++而言,預定義宏分為兩大類:ANSI C 預定義宏、微軟C++預定義宏。前者被絕大多數C++編譯器支持,后者只被微軟的VC++支持。
5.4.1 ANSI C 預定義宏
| 宏名 |
說明 |
示例 |
| __DATE__ |
文件的修改日期(本地時間)。asctime的返回值 |
"Oct 31 2009" |
| __FILE__ |
文件名,ANSI編碼。編譯時/FC控制是否含目錄。 下面的__WFILE__將是Unicode編碼的文件名 #define WIDEN2(x) L ## x #define WIDEN(x) WIDEN2(x) #define __WFILE__ WIDEN(__FILE__) |
"c:\\vcproj\\a.c" |
| __LINE__ |
所在的行號,是10進制的整數。可以被#line預編譯指令修改 |
5 |
| __STDC__ |
表示編寫的C代碼必須符合ANSI C標准。不能編譯C++代碼。 |
|
| __TIME__ |
文件的修改時刻(本地時間) |
"12:48:06" |
| __TIMESTAMP__ |
文件的修改日期時刻(本地時間) |
"Sat Oct 31 12:48:06 2009" |
5.4.2 微軟C++預定義宏
| 宏名 |
說明 |
| _ATL_VER |
ATL版本 |
| _CHAR_UNSIGNED |
char為無符號。指定/J后,該宏被定義 |
| __CLR_VER |
CLR(common language runtime)版本,其格式為Mmmbbbbb M 是主版本號 mm 是次版本號 bbbbb 是編譯版本號 |
| __cplusplus_cli |
Defined when compiling with /clr, /clr:pure, or /clr:safe. Value of __cplusplus_cli is 200406. __cplusplus_cli is in effect throughout the translation unit. |
| __COUNTER__ |
從0開始,出現一次增加1。可以用來產生讀一無二的變量名: // pre_mac_counter.cpp #include <stdio.h> #define FUNC2(x,y) x##y #define FUNC1(x,y) FUNC2(x,y) #define FUNC(x) FUNC1(x,__COUNTER__)
int FUNC(my_unique_prefix); int FUNC(my_unique_prefix); int main() { my_unique_prefix0 = 0; printf_s("\n%d",my_unique_prefix0); my_unique_prefix0++; printf_s("\n%d",my_unique_prefix0); } |
| __cplusplus |
如果使用C++編譯器,則該宏被定義 |
| _CPPLIB_VER |
Defined if you include any of the C++ Standard Library headers; reports which version of the Dinkumware header files are present. |
| _CPPRTTI |
編譯開關/GR被打開時,該宏被定義,表示支持運行時類型信息Run-Time Type Information |
| _CPPUNWIND |
Defined for code compiled with /GX (Enable Exception Handling). |
| _DEBUG |
Defined when compiling with /LDd, /MDd, and /MTd. |
| _DLL |
Defined when /MD or /MDd (Multithread DLL) is specified. |
| __FUNCDNAME__ |
Valid only within a function and returns the decorated name of the enclosing function (as a string). __FUNCDNAME__ is not expanded if you use the /EP or /P compiler option. |
| __FUNCSIG__ |
Valid only within a function and returns the signature of the enclosing function (as a string). __FUNCSIG__ is not expanded if you use the /EP or /P compiler option. On a 64-bit operating system, the calling convention is __cdecl by default. |
| __FUNCTION__ |
Valid only within a function and returns the undecorated name of the enclosing function (as a string). __FUNCTION__ is not expanded if you use the /EP or /P compiler option. |
| _INTEGRAL_MAX_BITS |
Reports the maximum size (in bits) for an integral type. |
| _M_ALPHA |
Defined for DEC ALPHA platforms (no longer supported). |
| _M_CEE |
Defined for a compilation that uses any form of /clr (/clr:oldSyntax, /clr:safe, for example). |
| _M_CEE_PURE |
Defined for a compilation that uses /clr:pure. |
| _M_CEE_SAFE |
Defined for a compilation that uses /clr:safe. |
| _M_IX86 |
Defined for x86 processors. See Values for _M_IX86 for more details. _M_IX86 = 300 /G3 80386 _M_IX86 = 400 /G4 80486 _M_IX86 = 500 /G5 Pentium _M_IX86 = 600 /G6 Pentium Pro, Pentium II, and Pentium III _M_IX86 = 600 /GB Blend(Default. Future compilers will emit a different value to reflect the dominant processor.) |
| _M_IA64 |
Defined for Itanium Processor Family 64-bit processors. |
| _M_IX86_FP |
Expands to a value indicating which /arch compiler option was used: 0 if /arch was not used. 1 if /arch:SSE was used. 2 if /arch:SSE2 was used. See /arch (Minimum CPU Architecture) for more information. |
| _M_MPPC |
Defined for Power Macintosh platforms (no longer supported). |
| _M_MRX000 |
Defined for MIPS platforms (no longer supported). |
| _M_PPC |
Defined for PowerPC platforms (no longer supported). |
| _M_X64 |
Defined for x64 processors. |
| _MANAGED |
Defined to be 1 when /clr is specified. |
| _MFC_VER |
MFC的版本 0x0600 VC++6.0/EVC3.0/4.0 0x0700 VC++7.0(VC2002) 0x0710 VC++7.1(VC2003) 0x0800 VC++8.0(VC2005) 0x0900 VC++9.0(VC2008) |
| _MSC_EXTENSIONS |
This macro is defined when compiling with the /Ze compiler option (the default). Its value, when defined, is 1. |
| _MSC_VER |
VC++的版本 1100 VC++5.0 1200 VC++6.0/EVC3.0 1201 EVC4.0 1300 VC++7.0(VC2002) 1310 VC++7.1(VC2003) 1400 VC++8.0(VC2005) 1500 VC++9.0(VC2008) |
| __MSVC_RUNTIME_CHECKS |
Defined when one of the /RTC compiler options is specified. |
| _MT |
Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd (Multithreaded) is specified. |
| _NATIVE_WCHAR_T_DEFINED |
Defined when /Zc:wchar_t is used. |
| _OPENMP |
Defined when compiling with /openmp, returns an integer representing the date of the OpenMP specification implemented by Visual C++. |
| _VC_NODEFAULTLIB |
Defined when /Zl is used; see /Zl (Omit Default Library Name) for more information. |
| _WCHAR_T_DEFINED |
Defined when /Zc:wchar_t is used or if wchar_t is defined in a system header file included in your project. |
| _WIN32 |
Defined for applications for Win32 and Win64. Always defined. |
| _WIN64 |
Defined for applications for Win64. |
| _Wp64 |
Defined when specifying /Wp64. |
| UNDER_CE _WIN32_WCE |
WinCE的版本 |
5.4.3 應用實例
下面的預處理指令將區分EVC++3.0、EVC++4.0、VC++6.0、VC++9.0
#ifdef _WIN32_WCE //智能設備
#if _MSC_VER==1200 //EVC3.0
#elif _MSC_VER==1201 //EVC4.0
#elif _MSC_VER==1500 //VC++9.0,即VC2008
#endif
#else
#if _MSC_VER==1200 //VC++6.0
#elif _MSC_VER==1500 //VC++9.0,即VC2008
#endif
#endif
5.5 預處理器操作符
5.5.1 #
增加雙引號,如下面的預編譯指令
#define STR(x) #x
編譯時,STR(123)將被預處理器替換為 "123"
5.5.2 #@
增加單引號,如下面的預編譯指令
#define CHR(x) #@x
編譯時,CHR(A)將被預處理器替換為 'A'
5.5.3 ##
連接字符串,如下面的預編譯指令
#define CAT(x,y) x##y
編譯時,CAT(ABC,123) 將被預處理器替換為 ABC123
5.5.4 defined
必須與條件編譯語句#if……#elif……#endif一起使用。
如:#ifdef _WIN32_WCE 與 #if defined(_WIN32_WCE) 等價。
如:#if defined(_WIN32_WCE) && _MSC_VER==1200 表示 EVC3.0 編譯器。
