VC(VisualC++)預(yù)處理及編譯_第1頁
VC(VisualC++)預(yù)處理及編譯_第2頁
VC(VisualC++)預(yù)處理及編譯_第3頁
VC(VisualC++)預(yù)處理及編譯_第4頁
已閱讀5頁,還剩65頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

預(yù)處理器特殊術(shù)語在本書中,名詞“參量”指的是傳送給ー個函數(shù)的實體。有時候,它用“actuaF聯(lián)“forma「修飾,它們分別用于表示函數(shù)調(diào)用時的參量表達(dá)式和在函數(shù)定義時的參量說明。名詞“變量’’指的是ー種簡單的C類型數(shù)據(jù)對象,名詞“對象”指的是C++對象和變量;它是ー個含義廣泛的名詞。翻譯階段C和C++程序由一個或多個源文件組成,它們都包含了程序的某些文本,ー個不包含代碼部分的源文件和它的包含文件(用#indude預(yù)處理器指令包含的文件),若被條件編譯指令(比如#if)調(diào)用,則稱其為ー個“轉(zhuǎn)換單元”。源文件可被翻譯多次,翻譯過去的文件事實上是很正常的。已經(jīng)翻譯了的翻譯單元可保存在單獨的對象文件或?qū)ο蟠a庫里,這些單個的轉(zhuǎn)換單元可被連接形成一個可執(zhí)行文件或動態(tài)鏈接庫(DLL)。轉(zhuǎn)換單元可采用下列形式通信:調(diào)用具有外部連接的函數(shù)。調(diào)用具有外部連接的類成員函數(shù)。直接更改具有外部連接的對象。文件的直接更改。?內(nèi)部外理通信(僅限于基于MicrosoftWindows的應(yīng)用程序)。以下是編譯器翻譯文件的各個階段:字符映射源文件中的字符被映射為內(nèi)部源代碼的形式。此階段三字母序列被轉(zhuǎn)換為單字符的內(nèi)部表現(xiàn)形式。行拼接在此階段,源文件中所有以反斜杠(ヽ)結(jié)尾且其后緊跟ー換行符的行,將與下一行連接,從而由物理行生成邏輯行。所有非空源文件結(jié)束于ー個前面沒有反斜杠的換行符。語言符號化此階段源文件被分為預(yù)處理語言符號和空白字符。源文件中每個注釋被用ー個空白字符代替。換行符被保留。預(yù)處理此階段執(zhí)行預(yù)處理指令并將宏擴(kuò)展至源文件,#include語句調(diào)用對所有包括文本啟動前面三個翻譯步驟開頭的翻譯過程。字符集映射所有的源字符集成員和轉(zhuǎn)義序列將轉(zhuǎn)換為執(zhí)行字符集中的等價形式,對于MicrosoftC和C++來說,源字符集和執(zhí)行字符集都是ASCI!碼。字符串合并所有相鄰的字符串和寬字符文字都將被合并。例如:"String""concatenatiorT合并為''Stringconcatenation”。翻譯所有的語言符號將按語法和語義規(guī)則進(jìn)行分析;這些語言符號被轉(zhuǎn)換為目標(biāo)代碼。鏈接此階段所有的外部引用被分解以生成一個可執(zhí)行程序或ー個動態(tài)鏈接庫。編譯器在翻譯過程中遇到語法錯誤時,將發(fā)出ー個警告或錯誤信息。鏈接器分解所有的外部引用,并把ー個或多個分開處理的轉(zhuǎn)換單元和標(biāo)準(zhǔn)庫聯(lián)接起來,以生成一個可執(zhí)行程序或動態(tài)鏈接庫(DLL)。預(yù)處理器指令預(yù)處理器指令如#define和#ifdef,一般被用在不同的運行環(huán)境下,使源程序易于更改和編譯。源文件中的指令指示預(yù)處理器執(zhí)行特有的行為。例如,預(yù)處理器可替換文本中的語言符號,將其它的文件內(nèi)容插入源文件中,或移走文本的一部分以抑制文件中某部分的編譯。預(yù)處理器行在宏擴(kuò)展之前被識別且執(zhí)行。不過,如果宏擴(kuò)展看起來象一個預(yù)處理器指令,該命令將不能被預(yù)處理器識別。除轉(zhuǎn)義序列之外,預(yù)處理器語句采用與源文件語句相同的字符集。在預(yù)處理器語句中的字符集和可執(zhí)行程序的字符集是ー樣的。預(yù)處理器也可識別負(fù)字符值。預(yù)處理器可識別如下指令:#define#error#import#undef#elif#if#include#else#ifdef#line#endif#ifhdef#pragma數(shù)字符號片)是包含預(yù)處理器指令的行中的第一個非空白字符??瞻鬃址沙霈F(xiàn)在數(shù)字符號和指令的第一個字母之間。某些指令包含參量和值。指令之后的任何文本(除作為指令一部分的參量或值之外)必須放在單行注釋分界符(〃)之后或注釋分界符(/**/)之間。預(yù)處理器指令可出現(xiàn)在源文件的任何地方,但它們僅用于源文件的剩余部分。#define指令可以用#define指令給程序中的常量取ー個有意義的名稱,其語法的兩種形式如下:語法#define標(biāo)識符語言符號字符串opt#define標(biāo)識符[(標(biāo)識符。pt,…,標(biāo)識符opt)]語言符號字符串opt#define指令用語言符號字符串替換源文件中一個標(biāo)識符的所有出現(xiàn),標(biāo)識符僅在它形成ー個語言符號時被替換(參見“MicrosoftVisualC++6.0參考庫”的“MicrosoftVisualC++6.0語言參考手冊”卷的第1章“詞法規(guī)定”中的“語言符號”)。例如,若標(biāo)識符出現(xiàn)在ー個注釋、ー個字符串或作為ー個長標(biāo)識符的一部分之中,它就不被替換。ー個不帶語言符號字符串的#define指令將移走源文件中每次標(biāo)識符的出現(xiàn)。標(biāo)識符保留其定義且能用#defined和#ifdef測試。語言符號字符串參量由一系列語言符號組成,如關(guān)鍵字、常量或完整的語句。一個或多個空白字符可將語言符號字符串和標(biāo)識符分開??瞻鬃址粫徽J(rèn)為是被替換文本的一部分,文本最后語言符號之后的空白也不會認(rèn)為是替換文本的一部分。形式參數(shù)名稱出現(xiàn)在語言符號字符串中以標(biāo)志出實際值被替換的位置,每個參數(shù)名稱可在語言符號字符串中出現(xiàn)多次,且可以以任何次序出現(xiàn)。調(diào)用時參量的數(shù)目必須與宏定義的參數(shù)數(shù)目相匹配。圓括號的自由運用可確保正確地說明復(fù)雜的實際參量。用第二種語法形式可創(chuàng)建類似函數(shù)的宏。這種形式接受一個用圓括號括起的可選參數(shù)表。在最初定義之后引用該標(biāo)識符,可以使用實際參量替代形式參數(shù)的語言符號字符串參量的形式,來替換標(biāo)識符(標(biāo)識符opt,…,標(biāo)識符opt)的每次出現(xiàn)。表中的形式參數(shù)必須用逗號隔開。該表中的每個名稱都必須是唯一的,且此參量表必須包括在圓括號中,標(biāo)識符和左邊的圓括號之間不能有空格。對于占用多行的長指令可使用行連接,把反斜杠(ヽ)放在換行符前。形式參數(shù)名稱的范圍延伸到結(jié)束語言符號字符串的換行符。當(dāng)一個宏以第二種語法形式定義時,參量表后的文本實例就構(gòu)成一個宏調(diào)用。在源文件中,一個標(biāo)識符實例后的實際參量必須與宏定義的相應(yīng)形式參數(shù)匹配。每個語言符號字符串之前無字符串化片)、字符化(#@)或語言符號粘貼併#)操作符,或其后無##操作符的形式參量,都被相應(yīng)的實際參量所替換。在指令替換形式參數(shù)之前,實際參量中的任何宏都將被擴(kuò)展(本章之后的“預(yù)處理器操作符’’中將介紹這些操作符)。以下帶參量宏的例子說明了#define語法的第二種形式:〃定義光標(biāo)行的宏#defineCURSOR(top,bottom)((top)?8)|bottom))〃獲取指定范圍中的一個隨機(jī)整數(shù)的宏#definegetrandom(min,max)\((rand()%(int)(((max)+l)-(min)))+(min))有副作用的參量有時會導(dǎo)致宏產(chǎn)生不希望的結(jié)果。ー個給定的形式參量在語言符號字符串中可能出現(xiàn)多次。如果該形式參數(shù)被ー個有副作用的表達(dá)式所替換,則該表達(dá)式及其副作用,可能被求值多次(參見本章后面“語言符號粘貼操作符##"中的例子)。#undef指令可使ー個標(biāo)識符的預(yù)處理器定義失效。有關(guān)的更多信息參見#undef指令。若一個被定義的宏名稱出現(xiàn)在語言符號字符串中(即使是另一個宏擴(kuò)展的結(jié)果),它將不被擴(kuò)展。除非第二次定義(#define)宏與原定義完全相同,否則重定義ー個已定義過的宏將產(chǎn)生一個錯誤信息。Microsoft特殊處MicrosoftC/C++允許ー個宏的重定義,但會產(chǎn)生一個警告信息,說明新的定義與原定義相同。ANSIC認(rèn)為宏的重定義是錯誤的。例如,下面的宏對C/C++是相同的,但會產(chǎn)生一個警告信息:#definetest(fl,f2)(fl*f2)#definetest(al,a2)(al*a2)Microsoft特殊處結(jié)束這個例子用于說明#define指令:#defineWIDTH80#defineLENGTH(WIDTH+10)第一個說明定義標(biāo)識符WIDTH為整形常量80,且用WIDTH和整形常量10定義LENGTH。LENGTH的每次出現(xiàn)都用(WIDTH+I0)所替換,接著,WIDTH+IO的每次出現(xiàn)都用表達(dá)式(80+10)替換。WIDTH+10的圓括號非常重要,因為它們決定著如下語句的解釋。vakLENGTH*20;經(jīng)預(yù)處理后該語句變?yōu)?vak(80+10)*20;求得值為1800,若無括號,結(jié)果為:var=80+10*20其值為280〇Microsoft特殊處在文件開頭用/D編譯器選項定義宏和常量,和用ー個#define預(yù)處理指令效果是ー樣的。能用/D選項定義的宏可達(dá)30個。Microsoft特殊處結(jié)束#error指令采用error指令可產(chǎn)生編譯錯誤信息。語法#error語言符號字符串錯誤消息包括語言符號字符串參量,且從屬于宏擴(kuò)展。這些指令對于檢測程序的前后矛盾和預(yù)處理時的違犯約束是非常有用的,以下例子說明了預(yù)處理時的出錯處理:#if!defined(_cplusplus)#errorC++compilerrequired.#endif當(dāng)遇到#error指令時,編譯終止。#if,#elif,#else和#endif指令#if、#elif、#else和#endif指令控制源文件中某部分的編譯。如果表達(dá)式併if之后)有一個非〇值,則緊跟在#if指令之后的行組將保留在轉(zhuǎn)換單元中。語法條件的:if部分elif部分optelse部分optendif行if部分:if行文本if行:#if常量表達(dá)式#ifhdef標(biāo)識符elif部分:elif行文本elif部分elif行文本elif行:#elif常量表達(dá)式else部分:else行文本else行:#elseendif行:#endif源文件中每個#if指令都必須與最近的ー個#endif相匹配。在#if和#endif指令之前的#elif指令的數(shù)目是不限的,但最多只能有一個#else指令。#else必須是#endif之前的最后ー個指令。#if、#elif、#else和#endif指令可嵌套在其它#if指令的文本部分。每個嵌套的#else、#elif或#endif指令應(yīng)屬于前面最近的ー個#if指令。所有的條件編譯指令,如#if和#ifdef,必須與文件結(jié)束前最近的#endif指令匹配;否則,將產(chǎn)生一個錯誤消息。當(dāng)條件編譯指令包括在包含文件中時,他們必須滿足相同的條件:在包含文件結(jié)尾沒有不匹配的條件編譯指令。宏替換應(yīng)在#elif命令后的命令行部分內(nèi)進(jìn)行,因此一個宏調(diào)用可用在常量表達(dá)式中。預(yù)處理器選擇ー個給定文本的出現(xiàn)之一作進(jìn)ー步的處理。文本中指定的ー個塊可以是文本的任何序列。它可能占用一行以上。通常該文本是對于編譯和預(yù)處理器有意義的程序文本。預(yù)處理器處理選擇文本并將其傳送給編譯器。若該文本包含預(yù)處理器指令,預(yù)處理器將執(zhí)行這些指令。編譯器只編譯預(yù)處理器選定的文本塊。預(yù)處理器通過求值每個#if或#elif指令之后的常量表達(dá)式直到找到ー個為真(非0)的常量表達(dá)式來選擇單個文本項。預(yù)處理器選擇所有的文本(包括以#開頭的其它預(yù)處理器指令)直到它關(guān)聯(lián)的#elif、#else或#endif。如果常量表達(dá)式的所有出現(xiàn)都為假,或者如果沒有#elif指令,預(yù)處理器將選擇#else后的文本塊。如果#else被忽略,且所有#if塊中的常量表達(dá)式都為假,則不選擇任何文本塊。常量表達(dá)式是一個有以下額外限制的整型常量表達(dá)式:表達(dá)式必須是整型且可以包括整型常量,字符常量和defined操作符。表達(dá)式不能使用sizeof或一個類型造型操作符。目標(biāo)環(huán)境不能表示整數(shù)的所有范圍。在翻譯表示中,int類型和10ng類型以及unsignedint類型和unsignedlong類型是相同的。翻譯器可將字符常量翻譯成一組不同于目標(biāo)環(huán)境的代碼值。為了確定目標(biāo)環(huán)境的屬性,應(yīng)在為目標(biāo)環(huán)境建立的應(yīng)用程序中檢測LIMITS.H的宏值。表達(dá)式不需執(zhí)行所有的環(huán)境查詢,但需與目標(biāo)計算機(jī)的執(zhí)行過程細(xì)節(jié)隔離開。預(yù)處理器操作符defined可用于特殊的常量表達(dá)式,語法如下:語法defined(標(biāo)識符)defined標(biāo)識符若此標(biāo)識符當(dāng)前已定義,則該常量表達(dá)式被認(rèn)為是真(非〇);否則,條件為假(0)。ー個定義為空文本的標(biāo)識符可認(rèn)為已定義。defined指令只能用于#if和#endif指令。在如下例子中,#if和#endif指令控制著三個函數(shù)調(diào)用中某ー個的編譯:ifdefined(CREDIT)credit();#elifdefined(DEBIT)debit();#elseprinterror();#endif若標(biāo)識符CREDIT已定義,則對于credit的函數(shù)調(diào)用被編譯。若標(biāo)識符DEBIT被定義,則對于debit的函數(shù)調(diào)用被編譯。若未定義任何標(biāo)識符,將編譯對于printerror的函數(shù)調(diào)用。注意,在C和C++中,CREDIT和credit是不同的標(biāo)識符,因為它們的大小寫不一樣。如下例子中的條件編譯語句給出了一個名稱為DLEVEL的已定義的符號常量:defineSIGNAL1ifSTACKUSE==1#defineSTACK200#else#defineSTACK100#endif#else#defineSIGNAL0#ifSTACKUSE=l#defineSTACK100#else#defineSTACK50#endif#endif#ifDLEVEL=0#defineSTACK0#elifDLEVEL=l#defineSTACK100#elifDLEVEL>5display(debugptr)滸else#endif第一個#if塊中有兩組嵌套的#if、#else和#endif指令。第一組指令僅當(dāng)DLEVEL1>5為真時執(zhí)行;否則,執(zhí)行#else之后的語句。第二組中的#elif和#else指令選擇基于DLEVEL值的四個選項之ー。常量STACK依據(jù)DLEVEL定義為〇,100或20〇。若DLEVEL大于5,則編譯語句:#elifDLEVEL>5display(debugptr);且此時不定義STACK〇條件編譯一般用于防止同一頭文件的多重包含。C++中在頭文件內(nèi)經(jīng)常定義類的位置,可使用如下結(jié)構(gòu)來防止多次定義。//EXAMPLE.H例子頭文件#if!defined(EXAMPLE_H)#defineExampleEHclassExample};#endif//!defined(EXAMPLE_H)上面的代碼用于檢查符號常量EXAMPLE_H是否已定義。若已定義,該文件就已被包括且不需再處理;如果未定義,常量EXAMPLE_H將被定義,以標(biāo)記EXAMPLE.H為已經(jīng)處理。Microsoft特殊處條件編譯表達(dá)式被看作為signedlong值,且這些表達(dá)式與C++中的表達(dá)式采用相同的規(guī)則求值。例如,表達(dá)式:#ifOxFFFFFFFFL>1UL為真。Microsoft特殊處結(jié)束#ifdef和ifndef指令#ifdef和#ifhdef指令與使用defined(標(biāo)識符)操作符的作用是ー樣的。語法#ifdef標(biāo)識符#ifhdef標(biāo)識符等同于#ifdefined標(biāo)識符#if!defined標(biāo)識符#if指令能用的任何地方都可以用#ifUef和#ifhdef指令。當(dāng)標(biāo)識符已被定義時,#ifdef標(biāo)識符語句等同于#if1;而當(dāng)標(biāo)識符未定義或用#undef指令對其反定義時,該語句等同于#if0。這些指令僅用于檢查C或C++源代碼中是否出現(xiàn)該標(biāo)識符,而不是用于檢查C或C++源程序中該標(biāo)識符的說明。提供這幾個指令只為了與該語言的老版本兼容。目前的趨勢是偏向于采用defined(標(biāo)識符)定義常量表達(dá)式的#if指令。#ifhdef指令測試與#ifdef相反的條件。若標(biāo)識符未定義(或已用#undef反定義),其條件為真(非0);反之,條件為假(0)。Microsoft特殊處可以使用/D選項從命令行傳送標(biāo)識符,采用/D選項至多可以指定30個宏。檢查ー個定義是否存在是非常有用的,因為定義可從命令行傳送。例如://prog.cpp#ifhdeftest〃這三個語句放在你的代碼中#definefinal#endifCL/Dtestprog.cpp〃這是編譯的命令Microsoft特殊處結(jié)束#import指令C-H"特殊處#import指令用于從ー個類型庫中結(jié)合信息。該類型庫的內(nèi)容被轉(zhuǎn)換為C++類,主要用于描述COM界面。語法#import”文件名"[屬性]#importく文件名>[屬性]屬性:屬性1,屬性2,...屬性1屬性2...文件名是ー個包含類型庫信息的文件的名稱。ー個文件可為如下類型之ー個類型庫(.TLB或.ODL)文件。ー個可執(zhí)行(.EXE)文件。ー個包含類型庫資源(如.OCX)的庫文件(.DLL)。ー個包含類型庫的復(fù)合文檔。其它可被LoadTypeLibAPI支持的文件格式。文件名之前可以有一個目錄規(guī)格。文件名必須是ー個已存在文件的名稱。兩種格式的區(qū)別是當(dāng)路徑未完全說明時,預(yù)處理器檢索類型庫文件的順序不同。動作語法格式引號格式這種格式讓預(yù)處理器首先搜索與包含#import語句的文件同一目錄的類型庫文件,然后在所有包括(include)該文件的目錄中搜索,最后在如下路徑中搜索尖括號格式這種格式指示預(yù)處理器沿以下路徑搜索類型庫文件編譯器在以下目錄中搜索已命名的文件:.PATH環(huán)境變量路徑表。.LIB環(huán)境變量路徑表。.用/1(額外的包括目錄)編譯器選項指定的路徑。#import可以任選地包含ー個或多個屬性。這些屬性使編譯器改變類型庫頭文件的內(nèi)容。ー個反斜杠。)符可用在ー個單ー的#import語句中包含額外的行,例如:#import"test.lib"no_namespace\rename("〇ldName","NewName")#import屬性列出如下:excludehigh_method_prefixhigh_property_prefixesimplementationonlyinclude(...)injectstatementnamedguidsno_auto_excludeno_implementationnonamespaceraw_dispinterfacesraw_interfaces_onlyraw_method_prefixrawnativetypesraw_property_prefixesrenamerename_namespace#import指令可創(chuàng)建兩個在C++源代碼中重構(gòu)類型庫內(nèi)容的頭文件,第一個頭文件和用Microsoft接口定義語言(MIDL)編譯器生成的頭文件類似,但有額外的編譯器生成代碼和數(shù)據(jù)。第一個頭文件與類型庫有相同的基本名,其擴(kuò)展名為.TLH。第二個頭文件也有與類型庫相同的基本名,其擴(kuò)展名為.TLI。它包括了編譯器生成成員函數(shù)的實現(xiàn),且被包含在併include)的第一個頭文件內(nèi)。兩個頭文件都在用/F。(命名對象文件)選項指定的輸出目錄中。隨后它們被讀出和編譯,就像第一個頭文件被#include指令命名ー樣。以下是伴隨#import指令的編譯器優(yōu)化:?頭文件被創(chuàng)建時,將被分配與類庫相同的時間標(biāo)志。?處理#import時,編譯器首先測試頭文件是否存在,是否過期。若條件為真,就不需重新創(chuàng)建。編譯器延遲對于OLE子系統(tǒng)的初始化,直到碰到第一個#import命令。#import指令也可參與最小重建且可被置于ー個預(yù)編譯頭文件中?;绢愋蛶祛^文件基本類型庫頭文件由七個部分組成:.頭部固定正文:由注釋、COMDEF.H(定義用在頭部的ー些標(biāo)準(zhǔn)宏)的include語句和其它繁雜的安裝信息組成。.前向引用和類型定義:由象structIMyinterface之類的結(jié)構(gòu)說明和用于ー些TKIND_ALIAS項的類型定義組成。.靈敏指針說明:模塊類_com_ptr_t是ー個封裝接口指針和消除調(diào)用AddRef、Release和Queryinterface函數(shù)需求的靈敏指針實現(xiàn)。此外,它隱藏了創(chuàng)建一個新COM對象中的CoCreatelnstance調(diào)用。此部分采用宏語句_COM_SMARTPTRTYPEDEF將COM接ロ的類型定義創(chuàng)建為_com_ptr_t模板類的模板特例化。例如,對于界面IFoo,.TLH文件包含有:_COM_SMARTPTRTYPEDEF(IFoo,__uuidof(IFoo));編譯器將其擴(kuò)展為:typedefcomptrt<comIIID<IFoo, uuidof(IFoo)?IFooPtr;類型IFooPtr可以用在原始的界面指針I(yè)Foo?的地方。結(jié)果,就不需調(diào)用各種IUnknown成員函數(shù)。.類型信息(typeinfo)說明:主要由類定義和其它項組成,這些項說明由ITyptLib:GetTypeInfo返回的單個的信息類型項目。在這部分,每個來自于類型庫的信息類型都以一種依賴于TYPEKIND信息的格式反映在該頭部。.任選舊式GUID定義:包含命名的GUID常量的初始化過程,這些定義是格式CLSID_CoClass和HD」nterface的名稱,與那些由MIDL編譯器產(chǎn)生的類似。.用于第二個類型庫頭部的#include語句。.結(jié)尾固定正文:目前包括#pragmapack(pop)。以上這些部分除頭部固定正文和結(jié)尾固定正文部分之外,都被包括在原來的IDL文件中以library語句指定其名稱的名稱空間中。你可以通過用名稱空間顯式限定或包括如下語句從類型庫頭部使用該名稱。usingnamespaceMyLib在源代碼的#import語句之后立即名稱空間可用#import指令的nonamespace屬性來阻止。但阻止的名稱空間可能導(dǎo)致名稱沖突。名稱空間也可用renamenamespace屬性重新?lián)Q名。編譯器提供完全路徑給需要依賴當(dāng)前正在處理的類型庫的任何類型庫。路徑以注釋格式寫入到由編譯器為每個處理的類型庫生成的類型庫頭部(.TLH)。如果ー個類型庫包含了對其它類型庫定義的類型引用,.TLH文件將包括以下注釋:////Cross-referencedtypelibraries:H//#import"c:\path\typelibO.tlb"http://在#import注釋中的實際文件名是存儲在寄存器中交叉引用的類型庫全路徑。如果你遇到由于省略類型定義的錯誤時,檢查.TLH頭部的注釋,看哪ー種依賴類型庫需要先輸入。在編譯該.TLI文件時可能的錯誤有語法錯誤(例如C2143,C2146,C2321)、C2501(缺少說明指示符)或C2433(在數(shù)據(jù)說明中禁止‘inline,)。你必須確定哪些依賴注釋是不被系統(tǒng)頭部給出的,而是在依賴類型庫的#import指令前的某處給出ー個#import指令以消除這些錯誤。exclude屬性exclude("稱ド[,“名稱2”,…])名稱1被排斥的第一個項名稱2被排斥的第二個項(如有必要)類型庫可能包含在系統(tǒng)頭部或其它類型庫內(nèi)定義的項的定義。該屬性可用于從生成的類型庫頭文件中排斥這些項。這個屬性可帶任意數(shù)目的參量,每個參量是一個被排斥的高級類型庫項目:highmethod_prefix屬性highmethod_prefix("Prefix")Prefix被使用的前綴在缺省的情況下,高級錯誤處理屬性和方法用一個無前綴命名的成員函數(shù)來展示。這個名稱來自于類型庫。high_methodjprefix屬性說明一個前綴以用于命名這些高級屬性和方法。high_property_prefixes屬性high_property_prefixes("GetPrefix,""PutPrefix,""PutRefPrefix")GetPrefix用于propget方法的前綴PutPrefix用于propput方法的前綴PutRefPrefix用于propputref方法的前綴在缺省情況下,高級錯誤處理方法,如propget>propput和propputref,分別采用以前綴Get、Put和PutRef命名的成員函數(shù)來說明。high_property_prefixes屬性用于分別說明這三種屬性方法的前綴。implementation_only屬性implementationonly屬性禁止.TLH頭文件(基本頭文件)的生成。這個文件包括了所有用于展示類型庫內(nèi)容的說明。該.TLI頭文件和wrapper成員函數(shù)的實現(xiàn),將被生成且包含在編譯過程中。當(dāng)指定該屬性時,該.TLI頭部的內(nèi)容將和用于存放普通.TLH頭部的內(nèi)容放在相同的名稱空間。此外,該成員函數(shù)不會作為聯(lián)編說明。implementationonly屬性一般希望與noimplementation屬性配對使用,以跟蹤預(yù)編譯頭文件(PCH)之外的實現(xiàn)。ー個有no_implementation屬性的#import語句被置于用來創(chuàng)建peh的源區(qū)域中,結(jié)果PCH將被ー些源文件所用。ー個帶implementation_only屬性的#import語句隨后被用在PCH區(qū)域之外。在一個源文件里只需用一次這種語句。這將生成不需對每個源文件進(jìn)行額外重編譯的所有必要的wrapper成員函數(shù)。注意:ー個#import語句中的implementation_only屬性必須和相同類型庫中no_implementation屬性的另ー個#import語句配套使用。否則,將產(chǎn)生編譯錯誤。這是因為帶noimplementation屬性的#import語句生成的wrapper類定義需要編譯implementation_only屬性生成的語句實現(xiàn)。include^..)屬性Include(名稱1[,名稱2,…])名稱1第一個被強(qiáng)制包含的項名稱2第二個被強(qiáng)制包含的項(如果必要)類型庫可能包含在系統(tǒng)頭部或其它類型庫中定義的項的定義。#import指令試圖用自動排斥這些項來避免多重定義錯誤。若這些項已經(jīng)被排斥,象警告C4192所指出的那樣,且它們不應(yīng)該被排斥,則這個屬性可用于禁止自動排斥。該屬性可帶任意數(shù)目的參量,每個參量應(yīng)是被包括的類型庫項的名稱。inject_statement屬性inject_statement("source_text")sourcetext被插入到類型庫頭文件的源文本。inject_statement屬性將其參量作為源文本插入類型庫頭部。此文本被置于包括頭文件中類型庫內(nèi)容的名稱空間說明的起始處。named_guids屬性namedguids屬性讓編譯器定義和初始化模板LIBIDMyLib、CLSIDMyCoClass^IIDMyInterface和DIIDMyDispInterface的舊式格式的GUID變量。no_implementation屬性該屬性阻止.TLI頭文件的生成,這個文件包含wrapper成員函數(shù)的實現(xiàn)。如果指定這個屬性,則展示類型庫項說明的.TLH頭將生成沒有一個#include語句包括該.TLI頭文件。該屬性與implementation_only屬性配套使用。no_auto_exclude屬性類型庫可能包括在系統(tǒng)頭部或其它類型庫中定義的項的定義。#import試圖通過自動排斥這些項來避免多重定義錯誤。當(dāng)這樣做時,每個被排斥的項都將生成一個C4192警告信息。你可禁止這個屬性使用自動排斥。no_namespace屬性#import頭文件中的類型庫內(nèi)容一般定義在ー個名稱空間里。名稱空間的名稱在原來IDL文件的library語句中指定。如果指定no_namespace屬性,編譯器就不會生成這個名稱空間。如果你想使用ー個不同的名稱空間,應(yīng)代替使用rename_namespace屬性。raw_dispinterfaces丿禹性rawdispinterfaces屬性讓編譯器生成一個低級wr叩per函數(shù)。該函數(shù)用于調(diào)用IDispatch::Invoke和返回HRESULT錯誤代碼的dispinterface方法和屬性。如果未指定此屬性,則只生成高級wrapper,它在失敗時丟棄該C++異常。raw_interfaces_only屬性raw_interfaces_only屬性禁止生成錯誤處理wrapper函數(shù)以及使用這些wrapper函數(shù)的declspec(屬性)說明。raw_interfaces_only屬性也導(dǎo)致刪除在命名non_property函數(shù)中的缺省前綴。通常該前綴是raw_。若指定此屬性,函數(shù)名稱將直接從類型庫中生成。該屬性只允許展示類型庫的低級內(nèi)容。raw_method_prefix屬性raw_method_prefix("Prefix")Prefix被使用的前綴用raw_作為缺省前綴的成員函數(shù)展示低層屬性和方法,以避免與高級錯誤處理成員函數(shù)的名稱沖突。raw_method_prefix屬性用于指定一個不同的前綴。注意:raw_method_prefix屬性的效果不會因raw_method_prefix屬性的存在而改變。在說明一"個前綴時,raw_method_prefix總是優(yōu)先于raw_interfaces_only〇若兩種屬性用在同一個#import語句中時,則采用raw_method_prefix指定的前綴。raw_native_types屬性在缺省情況下,高級錯誤處理方法在BSTR和VARIANT數(shù)據(jù)類型和原始COM界面指針的地方使用COM支持類_bctr_t和一variant]。這些類封裝了分配和取消分配這些數(shù)據(jù)類型的存儲器存儲的細(xì)節(jié),并且極大地簡化了類型造型和轉(zhuǎn)換操作。raw_native_types屬性在高級wrapper函數(shù)中禁止使用這些COM支持類,并強(qiáng)制替換使用低級數(shù)據(jù)類型。raw_property_prefix屬性raw_propertyprefix("GetPrefix","PutPrefix","PutRefPrefix")GetPrefix用于propget方法的前綴PutPrefix用于propput方法的前綴PutRefPrefix用于propputref方法的前綴在缺省情況下,低級方法propget、propput和propputref分別用后綴為get_>put_和putreし的成員函數(shù)來展示。這些前綴與MIDL生成的頭文件中的名稱是兼容的。raw_property_prefixes屬性分別用于說明這三個屬性方法的前綴。rename屬性rename("〇IdName,""NewName")OldName類型庫中的舊名NewName用于替換舊名的名稱rename屬性用于解決名稱沖突的問題。若該屬性被指定,編譯器將在類型庫中的OldName的所有出現(xiàn)處用結(jié)果頭文件中用戶提供的NewName替換。此屬性用于類型庫中的一個名稱和系統(tǒng)頭文件中的宏定義重合時。若這種情況未被解決,則將產(chǎn)生大量語法錯誤,如C2059和C2061o注意:這種替換用于類型庫的名稱,而不是用于結(jié)果頭文件中的名稱。這里有一個例子:假設(shè)類型庫中有一個名稱為MyParent的屬性,且頭文件中定義了一個用在#import之前的宏GetMyParent〇由于GetMyParent是用于錯誤處理屬性get的ー個wrapper函數(shù)的缺省名稱,所以將產(chǎn)生一個名稱沖突。為解決這個問題,使用#imp〇rt語句中的以下屬性:rename("MyParent",''MyParentX")該語句將重新命名類型庫中的名稱MyParent,而試圖重新命名GetMyParentwrapper名稱將會出錯:rename("GetMyParent","GetMyParentX")這是因為名稱GetMyParent只出現(xiàn)在結(jié)果類型庫頭文件中。rename_namespace屬性rename_namespace("NewName")NewName名稱空間的新名稱renamenamespace屬性用于重新命名包含類型庫內(nèi)容的名稱空間。它帶有一個指定名稱空間新名newname的參量。消除名稱空間可以使用nonamespace屬性。C++特殊處結(jié)束#include指令include指令告訴預(yù)處理器處理一個指定文件的內(nèi)容,就象這些內(nèi)容以前就在這條指令出現(xiàn)的源程序中。你可以把常量和宏定義放在包含文件中,然后用#include指令把這些定義加到任何源文件中。包含文件對于外部變量和復(fù)雜數(shù)據(jù)類型結(jié)合的說明也是有用的。你只需在為此目的創(chuàng)建的ー個包含文件中定義和命名這些類型ー次。語法#include"path-spec"#includepath_spec是ー個前面有目錄說明的任選文件名。這個文件名必須命名ー個現(xiàn)存文件。path_spec的語法依賴于編譯該程序的操作系統(tǒng)。這兩種語法格式都導(dǎo)致用已說明的包含文件的全部內(nèi)容來替換該指令。兩種格式的區(qū)別在于路徑未完整指定時預(yù)處理器搜索頭文件的順序。語法格式動作引號格式這種格式指示預(yù)處理器先在包含#include語句的文件的相同目錄內(nèi)搜索,然后在任何包括該文件的目錄中搜索。隨后預(yù)處理器沿著7!編譯器選項指定的路徑搜索,最后是在!NCLUDE環(huán)境變量說明的路徑搜索尖括號格式這種格式指示預(yù)處理器首先在/1編譯器選項指定的路徑中搜索包含文件。然后在INCLUDE環(huán)境變量說明的路徑中搜索一旦預(yù)處理器找到指定文件,它就立即停止搜索。如果用雙引號給出一個明確完整的包含文件的路徑,預(yù)處理器將只搜索該路徑規(guī)格而忽略標(biāo)準(zhǔn)目錄。如果在雙引號間的文件名不是ー個完整的路徑規(guī)格,預(yù)處理器將先搜索“父”文件的目錄。父文件是一個包含#include指令的文件。例如,如果你把名稱為file2的文件包括在ー個名稱為file!的文件中,filel就是父文件。包含文件可被嵌套;這指的是ー個#include指令出現(xiàn)在以另ー個#include指令命名的文件里。例如,以上的文件file2,可包含文件file3,在這種情況下,filel是file2的父文件,而且是file3的祖父文件。當(dāng)包含文件嵌套時,目錄搜索首先由父文件的目錄開始,然后,搜索祖父文件的目錄。因此,搜索從包含當(dāng)前處理源文件的目錄開始,若文件未找到,搜索就轉(zhuǎn)到/I編譯器選項指定的目錄,最后搜索include環(huán)境變量指定的目錄。下面的例子給出使用尖括號的文件包括:#include這個例子把名稱為STDIO.H的文件內(nèi)容加入到源程序中。尖括號指示預(yù)處理器在搜索完/1編譯器選項說明的目錄之后,搜索STDIO.H的環(huán)境變量指定的目錄。下面的例子給出用引號格式的文件包括:#include"defs.h"這個例子把DEFS.H指定的文件內(nèi)容加入源程序。雙引號標(biāo)記意味著預(yù)處理器首先搜索包含父源文件的目錄。包含文件的嵌套可高達(dá)10層,只要在處理嵌套的#include指令時,預(yù)處理器就會不斷地把包含文件加入到最初的源文件中。Microsoft特殊處為了定位可包括源文件,預(yù)處理器首先搜索/1編譯器選項指定的目錄。若/I選項未給定或已失敗,預(yù)處理器就用INCLUDE環(huán)境變量搜索尖括號內(nèi)的包含文件。INCLUDE環(huán)境變量和/1編譯器選項可包含用分號分開的多個路徑。若在/1選項的部分或在INCLUDE環(huán)境變量里有多于ー個的目錄,預(yù)處理器將以它們出現(xiàn)的順序?qū)λ鼈冞M(jìn)行搜索。例如,命令:CL/ID:\MSVC\INCLUDEMYPROG.C導(dǎo)致預(yù)處理器在目錄D:\MSVC\INCLUDE中搜索諸如STDIO.H的包含文件。命令:SETINCLUDE=D:\MSVC\INCLUDECLMYPROG.C有相同的作用。如果所有搜索都失敗了,將產(chǎn)生一個致命編譯錯誤。如果用包括ー個冒號的路徑(例如,F:\MSVC\SPECIAL\INCL\TEST.H)來完整地說明一個包含文件的文件名,預(yù)處理器將沿此路徑搜索。對于指定為#include"path_spec"的包含文件,目錄搜索將從父文件的目錄開始,然后搜索祖父文件的目錄。因此,搜索將從包含當(dāng)前處理的#include指令的源文件的目錄開始,如果沒有祖父文件或文件未找到,搜索將繼續(xù),就像文件名包括在尖括號中一樣。Microsoft特殊處結(jié)束#line指令#line指令告訴預(yù)處理器將編譯器內(nèi)部存儲的行號和文件名轉(zhuǎn)變?yōu)橐粋€給定的行號和文件名。編譯器使用該行號和文件名指出編譯過程中發(fā)現(xiàn)的錯誤。行號一般指的是當(dāng)前輸入行,文件名指當(dāng)前輸入文件。每處理一行,行號就增lo語法#line數(shù)字序列"文件名''opt數(shù)字序列的值可以是任何整型常數(shù)。宏替換可在預(yù)處理語言符號中執(zhí)行,但結(jié)果必須求值為正確的語法。文件名可以是任意字符的組合,且應(yīng)括在雙引號("“)間。如果省略文件名,則前面的文件名保持不變。你可以通過編寫ー個#line指令來改動源行號和文件名。翻譯器使用行號和文件名來確定預(yù)定義宏一FILE__和__LINE__的值。你可以使用這些宏把自描述錯誤消息加入到程序文本中。有關(guān)這些宏的更多信息參見預(yù)定義的宏。_FILE__宏擴(kuò)展成內(nèi)容為用雙引號("")括起的文件名的ー個字符串。如果你改變行號和文件名,編譯器將忽略原有的值,用新值繼續(xù)處理。#line指令通常被程序生成器用來生成指向最初源程序的錯誤消息,而不是生成程序。下面的例子用于說明#line以及LINE和FILE宏。在這個語句中,內(nèi)部存儲的行號設(shè)置為151,文件名改為copy.co#line151"copy.c"在這個例子中,若一個給定的“斷言”(assertion)不為真,則宏ASSERT使用預(yù)定義宏_LINE__和__FILE__打印出一個關(guān)于源文件的錯誤消息。#defineASSERT(cond)if(!(cond))\{prints"assertionerrorline%d,file(%s)\n",\_LINE__,__FILE_J;}Null指令空預(yù)處理器指令是一行中一個單獨的數(shù)字標(biāo)號片),無任何作用。語法#undef指令正如其名所隱含的,#undef指令取消(反定義)一個原來由#define指令創(chuàng)建的名稱。語法#undef標(biāo)識符#undef指令取消標(biāo)識符的當(dāng)前定義。其結(jié)果是,標(biāo)識符的每次出現(xiàn)都將被預(yù)處理器所忽略。為取消ー個用#undef的宏定義,只須給出宏的標(biāo)識符,不須給出參數(shù)表。你也可以將#undef指令用于ー個原來未定義的標(biāo)識符。這將確認(rèn)這個標(biāo)識符是未定義的。宏替換不能在#undef語句中執(zhí)行。#undef指令通常和一個#define指令匹配,以在源程序中創(chuàng)建一個區(qū)域,在這個區(qū)域中一個標(biāo)識符有其特定的含義。例如,源程序的一個特有函數(shù)可以使用顯式常量定義不影響程序余下部分的環(huán)境特定值。#undef指令也可與#if指令配對以控制源程序的條件編譯過程。有關(guān)更多信息參見“#if、#elif>#else和#endif指令’‘〇下面的例子中,#undef指令取消了一個符號常量和一個宏的定義,注意該指令只給出了宏的標(biāo)識符。#defineWIDTH80#defineADD(X,Y)(X)+(Y)...#undefWIDTH#undefADDMicrosoft特殊處宏可通過采用/U選項的命令行反定義,此命令行后跟反定義的宏名稱。此命令與在文件開頭處的#undef宏名稱語句序列的作用是相等的。Microsoft特殊處結(jié)束預(yù)處理器操作符#define指令的文本中有四種預(yù)處理器特有的操作符(它們的總結(jié)參見下面的表)。字符化、字符串化和語言符號粘貼操作符將在下面三章中討論。defined操作符的信息參見“#if、#elif、#else和#endif指令”。運算符動作字符串化操作符伊)將相應(yīng)實參置于雙引號內(nèi)字符化操作符併@)將相應(yīng)的參量置于單引號內(nèi),且將其作為字符處理(Microsoft特殊處)語言符號粘貼操作符(種)可將語言符號作為實參使用,且將其合并為其它的語言符號續(xù)表定義的操作符簡化在某特定宏指令中復(fù)合表達(dá)式的寫法字符串化操作符併)數(shù)字符號或“字符串化”操作符併)將宏參數(shù)(擴(kuò)展后)轉(zhuǎn)化為字符串常量。它只用于帶參量的宏。如果它在宏定義中的一個形式參量之前,宏調(diào)用傳給的實際參量就被括在雙括號中,且被看作為ー個字符串文字。然后該字符串文字將替換該宏定義中操作符和形參組合的每次出現(xiàn)。實參的第一個語言符號之前和最后ー個語言符號之后的空白被忽略。實參中語言符號之間的所有空白在結(jié)果字符串語義中都被看作為ー個空格。因此,若實參中的一個注解出現(xiàn)在兩個語言符號之間,它將被看作為一個空格。結(jié)果字符串文字自動地與任何僅用空格分開的相鄰字符串文字連接。此外,如果ー個包含在參量里的字符在用作一個字符串文字(例如,雙引號(つ或反斜杠。)字符)時通常需要一個轉(zhuǎn)義序列,必要的轉(zhuǎn)義反斜杠被自動地插入字符之前。下面的例子給出了一個包含字符串化操作符的宏定義和一個調(diào)用該宏的main函數(shù):Sdefinestringer(x)printf(#x,\n")voidmain()stringer(Inquotesintheprintffunctioncall\n);stringer(z,Inquoteswhenprintedtothescreen"\n);stringer("This:ヽ“printsanescapeddoublequote");)這種調(diào)用在預(yù)處理時會被擴(kuò)展,產(chǎn)生如下代碼:voidmain(){printf(/zInquotesintheprintffunctioncall\n""\n");printf("\'Tnquoteswhenprintedtothescreen、'\n\n);printf("ヽ"This;\\\"printsanescapeddoublequote\"""\n");)當(dāng)運行該程序時,每行的屏幕輸出如下:Inquotesintheprintffunctioncall"Inquoteswhenprintedtothescreen""This;\"printsanescapeddoublequotationmark"Microsoft特殊處MicrosoftC(版本6.0及更早版本)擴(kuò)展ANSIC的標(biāo)準(zhǔn),ANSIC擴(kuò)展在字符串文字和字符常量中出現(xiàn)的宏形式參量不再被支持。依賴于此擴(kuò)展的代碼應(yīng)該使用字符串化操作符併)重寫。Microsoft特殊處結(jié)束字符化操作符併@)Microsoft特殊處字符化操作符只可用于宏參量,若宏定義中#@在ー個形參前,則實參應(yīng)被放在單引號中,在宏擴(kuò)展時作為ー個字符處理。例如:#definemakechar(x)#@x將語句:a=makechar(b);擴(kuò)展為:a=rb';單引號字符不能用于字符化操作符。Microsoft特殊處結(jié)束語言符號粘貼操作符併#)雙數(shù)字語言符號或“語言符號粘貼”操作符(種),有時稱作“合并‘‘操作符,用于類對象宏和類函數(shù)宏中。它允許將分開的語言符號加入一個單個語言符號中,因此不能是宏定義的第一個語言符號或最后ー個語言符號。如果ー個宏定義中的形參在語言符號粘貼操作符的前后,則形參將立即被未擴(kuò)展的實參替換。在替換之前不對參量執(zhí)行宏擴(kuò)展。然后,語言符號字符串中語言符號粘貼操作符的每次出現(xiàn)將被刪除,其前后的語言符號將被合并。其結(jié)果語言符號必須是ー個有效的語言符號。若其有效,如果該語言符號代表ー個宏名稱,則掃描它以發(fā)現(xiàn)可能的替換。該標(biāo)識符表示在替換前程序中己知合并的語言符號的名稱。每個語言符號都代表ー個在程序中或在編譯器命令行中定義的語言符號。該操作符前后的空白是任意的。如下例子說明了程序輸出中字符串化操作符和語言符號粘貼操作符的用法:#definepaster(n)printf("token"#n"=%d",taken##n)inttoken9=9;若一個宏用ー個類似于下面的數(shù)值參量調(diào)用:paster(9);宏將生成:printf("token""9""=%d",token9);它變成為:printf("token9=%d",token9);宏對宏擴(kuò)展的預(yù)處理在所有那些不是預(yù)處理指令的行(第一個非空白字符不是#的行),以及其指令并未作為條件編譯的一部分而忽略的行中進(jìn)行?!皸l件編譯’‘指令允許通過檢測ー個常量表達(dá)式或標(biāo)識符以決定在預(yù)處理過程中哪個文本塊送入編譯器、哪個文本塊從源文件中刪除,并以此種方式控制ー個源文件中某部分的編譯。#define指令通常使用有意義的標(biāo)識符與常量、關(guān)鍵字、常用語句和表達(dá)式關(guān)聯(lián)。表示常量的標(biāo)識符有時被稱作“符號常量’’或"顯式’‘常量。表示語句或表達(dá)式的常量稱為“宏'在本預(yù)處理器文檔中,只使用術(shù)語“宏'當(dāng)宏的名稱在程序源文本或在某些其它預(yù)處理器命令的參量中被識別時,它被處理為對該宏的調(diào)用。宏名稱被宏體的ー個拷貝所替換。若該宏接受參量,宏名稱后的實參就會替換宏體中的形參。用宏體中處理的拷貝來替換ー個宏調(diào)用的過程,稱為宏調(diào)用的“擴(kuò)展”。實際的術(shù)語中有兩種類型的宏?!邦悓ο?'宏不帶參量,而“類函數(shù)”宏可定義為帶參量。因此它們的形式和功能都象函數(shù)調(diào)用,由于宏不生成實際的函數(shù)調(diào)用,所以有時可用宏替代函數(shù)調(diào)用使程序運行得更快,(在C++中,inline函數(shù)通常是一個好方法),然而,如果不小心的定義和使用宏,也可能造成麻煩。在帶參量的宏定義時,你必須使用括號以保持ー個表達(dá)式中正常的優(yōu)先級,同時宏也不能正確地處理具有副作用的表達(dá)式。有關(guān)更多的信息參見“#define指令''中的例子getrandom。一旦你定義了一個宏,你不能不經(jīng)取消該宏原有定義,而重新定義它為ー個不同的值。但可用正好相同的定義來重定義該宏,因此,ー個程序中宏的相同定義可出現(xiàn)多次。#undef指令用于取消宏的定義。一旦取消該宏的定義,就可重新定義該宏為ー個不同的值。#define和#undef兩節(jié)分別詳細(xì)討論了#define和#undef指令。宏和C++C++提供了一些新的功能。其中有些功能替代了原來由ANSIC所提供的功能。這些新的功能增強(qiáng)了類型安全性和該語言的可預(yù)測性:在C++中,以const說明的對象可用于常量表達(dá)式中,這使程序說明有類型和值信息的常量,以及能被調(diào)試器逐個字符檢查的枚舉值的常量。使用預(yù)處理器指令#define定義常量并不精確。除非在程序中找到ー個帶地址的表達(dá)式,否則ー個const對象將不分配任何存儲。C++聯(lián)編函數(shù)替代了函數(shù)類型宏,相對于宏來說使用聯(lián)編函數(shù)的優(yōu)勢在于:類型安全性。聯(lián)編函數(shù)和一般函數(shù)ー樣需進(jìn)行相同的類型檢測,宏無類型安全性檢測。糾正具有副作用的參量處理。聯(lián)編函數(shù)在進(jìn)入函數(shù)體之前對參量的表達(dá)式求值。因此,ー個有副作用的表達(dá)式將是安全的。對于聯(lián)編函數(shù)的更多信息參見inline、__inline節(jié)。為了向下兼容,Micros。仕C++保留了所有在ANSIC和更早C++規(guī)格中的預(yù)處理器功能。預(yù)定義宏編譯器可識別六種預(yù)定義的ANSIC宏(參見表1.1),而MicrosoftC++實現(xiàn)提供更多的預(yù)定義宏(參見表1.2)。這些宏不帶參量,但不能被重定義。它們的值(除_LINE__和__FILE__外)必須是經(jīng)過編譯的常量。下面列出的一些預(yù)定義宏須用多個值來定義,它們的值可在VisualC++開發(fā)環(huán)境中選擇相應(yīng)的菜單選項來設(shè)置或采用命令行開關(guān)。更多的信息參見下表。表1.1ANSI預(yù)定義宏宏說明_DATEー當(dāng)前源文件的編譯日期。日期是格式為Mmmddyyyy的字有串文字。月份名稱Mmm與在TIME.H中說明的庫函數(shù)asctime產(chǎn)生的日期ー樣_FILE__當(dāng)前源文件名稱。_FILE_JT展為用雙引號括起的一個字符串_LINE當(dāng)前源文件的行號。該行號是一個十進(jìn)制整型常量??捎茅`個#line指令修改_STDC__指出與ANSIC標(biāo)準(zhǔn)的完全一?致性。僅當(dāng)給出/Za編譯器選項且不編譯C++代碼時定義為整型量1;否則是不確定的_TIME__當(dāng)前文件的最近編譯時間。該時間是格式為hh:mm:ss的字符串文字_TIMESTAMP_當(dāng)前源文件的最近修改日期。日期是格式為DddMmmDatehh:mm:ssyyyy的字符串文字,這里Ddd是星期兒的簡寫,Date是從1到31的二個整數(shù)表表1.2Microsoft特殊預(yù)定義的宏宏說明CHARUNSIGNED缺省char類型是無符號的,當(dāng)指定/J時定義的cplusplus僅為C++程序定義CPPRTTI定義為用/GR編譯的代碼(允許運行時類型信息)CPPUNWIND定義為用/GX編譯的代碼(允許異常處理)DLL指定/MD或/MDd(多線程DLL)時定義的

_M_ALPHA為DECALPHA平臺定義,使用ALPHA編譯器時定義為1,若使用另ー個編譯器時不定義_M_IX86為x86處理器定義,參見表1.3_M_MPPC為PowerMacintosh平臺定義,缺省為601(/QP601)參見表1.4_M_MRXOOO為MIPS平臺定義,缺省為4000(/QMR400〇),參見表!,5_M_PPC為PowerPC平臺定義,缺省為604(/QP604),參見表1.6_MFC_VER為MFC版本定義,為MicrosoftFounndation類庫4.21定義為0x0421,它總是定義的_MSC_EXTENSIONS該宏在使用/Ze編譯選項(缺省值)時定義,定義時其值總為1_MSC_VER定義編譯器版本,對于MicrosoftVisualC++6.0定義為1200,它總是定義的_MT當(dāng)指定/MD或/MDd(多線程DLL)或/MT或/MTd(多線程)選項時定義_WIN32為Win32應(yīng)用程序而定義。它總是定義的如下表所示,編譯器對反映處理器選項的預(yù)處理器標(biāo)識符產(chǎn)生一個值。表1.3_M_IX86的值開發(fā)者的選項命令行選項返冋值Blend/GB_M」X86=500(缺省值。將來的編譯器將給出ー個不同的值以影響主處理器)Pentium/G5M1X86=500Pentiumpro/G6M1X86=60080386/G3M1X86=30080486/G4_M_IX86=400表1.4_M_MPPC的值開發(fā)者的選項命令行選項返回值PowerPC601/QP601_M_MPPC=601(缺省值)PowerPC603/QP603_M_MPPC=603PowerPC604/QP604_M_MPPC=604

PowerPC620|/QP620|MMPPC=620PowerPC620|/QP620|MMPPC=620表!.5MMRX000的值開發(fā)者選項命令行選項返回值R4000/QMR4000_M_MRX000=4000(缺省值)R4100/QMR4100_M_MRX000=4100R4200/QMR4200_M_MRX000=4200R4400/QMR4400_M_MRX000=4400R4600/QMR4600_M_MRX000=4600R10000/QMR10000_M_MRX000=10000表!.6_M_PPC的值開發(fā)者選項命令行選項返回值R4000/QMR4000_M_MRX000=4000(缺省值)R4100/QMR4100_M_MRX000=4100R4200/QMR4200_M_MRX000=4200R4400/QMR4400_M_MRX000=4400R4600/QMR4600_M_MRX000=4600RI0000/QMR10000_M_MRX000=10000編譯指示指令C++編譯器專有編譯指示C和C++的每個實現(xiàn)對它的主機(jī)或操作系統(tǒng)都支持ー些獨有的特征。例如,某些程序須對存放數(shù)據(jù)的存儲器區(qū)域進(jìn)行精確的控制,或必須控制特定函數(shù)接受參量的方式。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機(jī)或操作系統(tǒng)專有的特征。依據(jù)定義,編譯指示是機(jī)器或操作系統(tǒng)專有的,且對于每個編譯器都是不同的。語法#pragma語言符號字符串語言符號字符串是給出特有編譯器指令和參量的字符序列。數(shù)字符號(#)必須是包含編譯指示行中的第一個非空白字符??瞻鬃址煞珠_數(shù)字符號(#)和單詞pragma。在#pragma之后,可以編寫翻譯器作為預(yù)處理器語言符號分析的任何文本。#pragma的參量從屬于宏擴(kuò)展。如果編譯器找到ー個不能識別的編譯指示,將發(fā)出一個警告,但編譯將繼續(xù)。編譯指示可用在條件說明中,以提供新的預(yù)處理器功能,或提供定義的實現(xiàn)信息給編譯器。C和C++編譯器可識別下面的編譯指示:alloc_textcommentinitseg*optimizeautoinlinecomponentinlinedepthpackbss_segdataseginlinerecursionpointers_tomembers*checkstackfunctionintrinsicsetlocalecode_seghdrstopmessagevtordisp*constsegincludealiasoncewarning*僅被C++編譯器支持C++編譯器專有編譯指示以下是C++編譯器專有的編譯指示指令:initseglpointerstomembersvtordispinit_segC++特殊處#pragmainit-seg({complier/lib/user/"section-name"輸nc-name"[})該扌旨令指定一個影響啟動代碼執(zhí)行順序的關(guān)鍵字或代碼段。由于全局靜態(tài)對象的初始化可能涉及執(zhí)行代碼,因此必須指定創(chuàng)建對象時定義的ー個關(guān)鍵字。在動態(tài)連接庫(DLL)或需初始化的庫中使用init_seg編譯指示尤其重要。initseg編譯指示的選項如下:compiler該選項保留給MicrosoftC運行庫初始化。這個組中的對象最先被創(chuàng)建。lib用于第三方類庫供應(yīng)商的初始化。該組中的對象在complier標(biāo)志之后,其他標(biāo)記之前創(chuàng)建。user用于任何用戶。此組對象最后創(chuàng)建。sectionname允許初始化段的顯示規(guī)格。在ー個用戶指定section-name(段名稱)中的對象不能被隱含地創(chuàng)建,但它們的地址可放在以sectionname命名的段中。func_name指定在程序退出時在exit。地方調(diào)用的函數(shù)。指定的函數(shù)必須與exit函數(shù)具有相同的特征:intfuncname(void(_cdecl*)(void));如果你需要延遲初始化過程(例如,在ー個DLL中),你可以選擇顯式地指定該段名稱。然后必須為每個靜態(tài)對象調(diào)用構(gòu)造函數(shù)。C++特殊處結(jié)束pointers_to_membersC++特殊處#progmapointersto_members(指針說明」最一般表示])該指令指定一個類成員的指針能否在其相關(guān)定義之前被說明,且用于控制該指針尺寸和解釋該指針需要的代碼。你可以把ー個pointerstomembers編譯指示放入你的源文件中替換/vmx編譯器選項。指針說明參量指定你在ー個關(guān)聯(lián)函數(shù)定義之前還是之后說明了一個成員的指針。指針說明參量是以下兩個符號之一:參量時明生成安全、但常常并非最優(yōu)的代碼。如果在關(guān)聯(lián)類定義之前說明fullgenerality任何成員的指針,可使用fullgeneralityo該參量通常使用最?般表示參量指定的指針表示形式。等同于/vmg選項best_case為所有成員指針使用最佳情況(best_case)表示生成安全的最優(yōu)代碼。使用該參量是需在定義ー個類的成員指針說明之前定義此類。其缺省值為bestcasebestcase為所有成員指針使用最佳情況(best_case)表示生成安全的最優(yōu)代碼。使用該參量是需在定義ー個類的成員指針說明之前定義此類。其缺省值為best_case最一般表示參量說明了在轉(zhuǎn)換單元中,編譯器能夠安全地引用任何指向類成員的指針的最小指針表示。該參量取如下值之一:參量說明single_inheritance最ー一般表示是單繼承的,即ー個成員函數(shù)的指針。對于其中說明了一個指向成員指針的ー個類定義,若其繼承模式說明為多重的或虛擬的,將導(dǎo)致錯誤multiple_inheritance最一般表示是多重繼承的,即ー個成員函數(shù)的指針。對于其中說明了一個指向成員指針的ー個類定義,若其繼承模式是虛擬的,將導(dǎo)致錯誤vitualinheritance最一般表示是虛擬繼承,即ー個成員函數(shù)的指針。該函數(shù)不會導(dǎo)致錯誤。當(dāng)使用#pragmapointers_to_members(full_generality)時這是個缺省參量C++特殊處結(jié)束vtordispC++特殊處#pragmavtordisp({on|off})該指令允許增加隱含的vtordisp構(gòu)造函數(shù)/析構(gòu)函數(shù)替換成員。vtordisp編譯指示只使用虛基類的代碼。若一個派生類重迭ー個從虛擬基類繼承的虛擬函數(shù),且如果派生類的一個構(gòu)造函數(shù)或析構(gòu)函數(shù)調(diào)用那個使用該虛擬基類指針的函數(shù),則編譯器可能將增加的隱含“vtordisp”域到有虛擬基的類中。vtordisp編譯指示會影響其后類的分布。/VdO或”dl選項指定了對于完全模式的相同動作。指定off將抑制隱含的vtordisp成員。指定缺省值on,將在需要的位置打開它們。Vtordisp指令僅在類的構(gòu)造/析構(gòu)函數(shù)在用this指針指向的對象處不可能調(diào)用虛擬函數(shù)時關(guān)閉。#pragmavtordisp(off)classGetReal:virtualpublic{...};#pragmavtordisp(on)C++特殊處結(jié)束C和C++編譯器編譯指示以下是為C和C++編譯器定義的編譯指示:alloctextcomponentinitseg*optimizeautoinlineconstseginlinedepthpackbss_segdata_seginline_recursionpointers_tomembers*checkstackfunctionintrinsicsetlocalecode_seghdrstopmessagevtordisp*commentinclude_aliasoncewarning僅被C++編譯器支持alloc_text#pragmaallojtext(“文本段”,函數(shù)1,...)該指令用于命名指定的函數(shù)定義將要駐留的代碼段。該編譯指示對已命名的函數(shù)必須出現(xiàn)在ー個函數(shù)說明符和該函數(shù)定義之間。alloctjext編譯指示并不處理C++成員函數(shù)或重載函數(shù)。它僅用于以C連接方式說明的函數(shù),這指的是用extern“C”連接規(guī)格說明的函數(shù)。如果你試圖將此編譯指示用于非C++連接的函數(shù),將產(chǎn)生一個編譯錯誤。由于不支持使用—based的函數(shù)地址,指定段位址需要使用allocjext編譯指示,以文本段指定的名稱應(yīng)包括在雙引號間。alloctext編譯指示必須出現(xiàn)在指定的函數(shù)說明之后,這些函數(shù)的定義之前。ー個allocjext編譯指示中的函數(shù)引用必須在此編譯指示的同一模塊中定義。如果未這樣做,且ー個未定義的函數(shù)隨后被編譯到ー個不同的文本段,則這個錯誤可能找得到,也可能找不到。雖然該程序一般會正常運行,但該函數(shù)不會分配到預(yù)期的段中。alloctext的其他限制如下:?它不能用在ー個函數(shù)的內(nèi)部。?它必須在已說明的函數(shù)之后和已定義的函數(shù)之前使用。auto_mline#pragmaauto_inline([{on|off}])排除自動內(nèi)聯(lián)擴(kuò)展的候選者中指定為off的區(qū)域中定義的函數(shù)。為了使用auto_inline編譯指示,把它放在ー個函數(shù)定義之前或立即之后(不在該函數(shù)定義之內(nèi))。在看到該編譯指示之后的第一個函數(shù)定義處,該編譯指示發(fā)生作用。編譯指示auto_inline不能應(yīng)用于顯式內(nèi)聯(lián)函數(shù)。bss_seg#pragmadata-seg(["section-name"[,"section-class"]])指定未初始化數(shù)據(jù)的缺省段。data_seg編譯指示處理初始化或未初始化數(shù)據(jù)有相同的作用。在某些情況下,你可以使用bss_seg通過把所有未初始化數(shù)據(jù)放在ー個段中來加速加載的時間。#pragmabssseg("MYDATA")導(dǎo)致#pragma語句后未初始化的數(shù)據(jù)分配到ー個名稱為MY_DATA的段中。用bss_seg編譯指示分配的數(shù)據(jù)不會保留關(guān)于它的位置的任何信息。第二個參量section_class用于與VisualC++之前的版本兼容,現(xiàn)在已被忽略。check_stack#pragmacheck_stack([{on|off}])#pragmacheck_stack{+|-}該指令在off(或-)選項時指示編譯器關(guān)閉棧搜索。在on(或+)選項指定時,打開搜索。若無參量,棧搜索就按缺省情況處理。在看到該編譯指示之后第一個定義的函數(shù)處發(fā)生作用。棧搜索既不是宏的一部分,也不是產(chǎn)生的內(nèi)聯(lián)函數(shù)的一部分。如果未賦予ー個參量給check_stack編譯指示,棧檢查將還原成在命令行中說明的行為,有關(guān)更多的信息參見“編譯器參考“。#pragmacheck_stack和/Gs選項的交互關(guān)系參見表2.1〇表2.1使用check_stack編譯指示語法是否用/Gs選項編譯行為#pragmacheck_stack()或#pragmacheck_stack是關(guān)閉其后函數(shù)的棧檢查#pragmacheck_stack()或#pragmacheckstack否打開其后函數(shù)的棧檢查#pragmacheckstack(on)或#pragmacheck_stack+是或否打開其后函數(shù)的棧檢查#pragmacheckstack(off)或#pragmacheck_stack-是或否關(guān)閉其后函數(shù)的棧檢查code_seg#pragmacode_seg(["section-name"[,"section-class"]])該指令用于指定一個分配函數(shù)的代碼段。code_seg編譯指示指定了函數(shù)的缺省段。你可以有選擇性地指定類和段名。使用沒有section-name字符串的#pragmacode_seg可在編譯開始時將其復(fù)位。const_seg#pragmaconst_seg(["section-name"[,"section-class"]])該指令用于指定對于常量數(shù)據(jù)的缺省段。data_seg編譯指示對所有數(shù)據(jù)具有相同作用。你可以用此指令將你的所有常量數(shù)據(jù)放入一個只讀段中。#pragmaconstseg("MYDATA")導(dǎo)致該指令將#pragma語句后的常量數(shù)據(jù)放入ー個名稱為MYDATA的段里。使用const_seg編譯指示分配的數(shù)據(jù)不會保留有關(guān)它的位置的任何信息。第二個參數(shù)section-class用于與VisualC++2.0版之前的版本兼容,現(xiàn)在已可忽略。comment#pragmacomment(comment-type,[commentstring])該指令將一個注釋記錄放入ー個對象文件或可執(zhí)行文件中。comment-type是下面五種說明的預(yù)定義標(biāo)識符之一,它們指出了注釋記錄的類型。任選的commentstring是給ー些注釋類型提供額外信息的字符串文字。由于commentstring是ー個字符串文字,因此它必須遵循對于字符串文字的諸如轉(zhuǎn)義字符、嵌入或引號標(biāo)記(ッ以及合并的所有規(guī)則。compiler該選項將編譯器的名稱和版本號放入對象文件中。這個注釋記錄被鏈接器忽略,如果你為這個記錄類型給出ー個commentstring參量,該編譯器將產(chǎn)生一個警告信息。exestr該選項將commentstring放入對象文件中。在連接時,該字符串被置入可執(zhí)行文件中。該字符串并不與可執(zhí)行文件同時加載到存儲器,但它可用在文件中尋找可打印字符串的程序找到。這個注釋記錄類型的ー個用途是把版本號或類似信息嵌入到ー個可執(zhí)行文件中。lib該選項將一個庫搜索記錄放入對象文件。該注釋類型必須帶有一個commentstring參數(shù)。這個參數(shù)包含你想要的鏈接器搜索的庫的名稱(有可能包含路徑)。由于在對象文件中該庫名稱在缺省的庫搜索記錄之前,所以鏈接器搜索該庫就象你在命令行中命名了它ー樣。你可以把多個庫搜索記錄放在同一個源文件中,每個記錄在對象文件中都以其在

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論