| ?????? __declspec用于指定所給定類型的實(shí)例的與Microsoft相關(guān)的存儲(chǔ)方式。其它的有關(guān)存儲(chǔ)方式的修飾符如static與extern等是C和C++語(yǔ)言的ANSI規(guī)范,而__declspec是一種擴(kuò)展屬性的定義。擴(kuò)展屬性語(yǔ)法簡(jiǎn)化并標(biāo)準(zhǔn)化了C和C++語(yǔ)言關(guān)于Microsoft的擴(kuò)展。 用法:__declspec ( extended-decl-modifier ) extended-decl-modifier參數(shù)如下,可同時(shí)出現(xiàn),中間有空格隔開: align (C++) allocate appdomain deprecated (C++) dllimport dllexport jitintrinsic naked (C++) noalias noinline noreturn nothrow (C++) novtable process property(C++) restrict selectany thread uuid(C++) 1.__declspec關(guān)鍵字應(yīng)該出現(xiàn)在簡(jiǎn)單聲明的前面。對(duì)于出現(xiàn)在*或&后面或者變量聲明中標(biāo)識(shí)符的前面的__declspec,編譯器將忽略并且不給出警告。 2.要注意區(qū)分__declspec是修飾類型還是修飾變量: __declspec(align(8)) struct Str b;修飾的是變量b。其它地方定義的struct Str類型的變量將不受__declspec(align(8))影響。 __declspec(align(8)) struct Str {};修飾的是struct Str類型。所有該類型的變量都受__declspec(align(8))影響。 align: 格式:__declspec(align(n)) declarator 其中,n是對(duì)齊參數(shù),其有效值是2的整數(shù)次冪(從1到8192字節(jié)),如2,4,8,16,32或64。參數(shù)declarator是要設(shè)置對(duì)齊方式的數(shù)據(jù)。 1.使用__declspec(align(n))來精確控制用戶自定義數(shù)據(jù)的對(duì)齊方式。你可以在定義struct,union,class或聲明變量時(shí)使用__declspec(align(n))。 2.不能為函數(shù)參數(shù)使用__declspec(align(n))。 3.如果未使用__declspec(align(#)),編譯器將根據(jù)數(shù)據(jù)大小按自然邊界對(duì)齊。如4字節(jié)整數(shù)按4字節(jié)邊界對(duì)齊;8字節(jié)double按8字節(jié)邊界對(duì)齊。類或結(jié)構(gòu)體中的數(shù)據(jù),將取數(shù)據(jù)本身的自然對(duì)齊方式和#pragma pack(n)設(shè)置的對(duì)齊系數(shù)中的最小值進(jìn)行對(duì)齊。 4.__declspec(align(n))和#pragma pack(n)是一對(duì)兄弟,前者規(guī)定了對(duì)齊系數(shù)的最小值,后者規(guī)定了對(duì)齊系數(shù)的最大值。 5.當(dāng)兩者同時(shí)出現(xiàn)時(shí),前者擁有更高的優(yōu)先級(jí)。即,當(dāng)兩者同時(shí)出現(xiàn)且值矛盾時(shí),后者將不起作用。 6.當(dāng)變量size大于等于#pragma pack(n)指定的n,而且__declspec(align(n))指定的數(shù)值n比對(duì)應(yīng)類型長(zhǎng)度小的時(shí)候,這個(gè)__declspec(align(n))指定將不起作用。 7.當(dāng)#pragma pack(n)指定的值n大于等于所有數(shù)據(jù)成員size的時(shí)候,這個(gè)值n將不起作用。 allocate: 格式:__declspec(allocate("segname")) declarator 為數(shù)據(jù)指定存儲(chǔ)的數(shù)據(jù)段。數(shù)據(jù)段名必須為以下列舉中的一個(gè): code_seg const_seg data_seg init_seg section appdomain: 指定托管程序中的每個(gè)應(yīng)用程序域都要有一份指定全局變量或靜態(tài)成員變量的拷貝。 deprecated: 與#pragma deprecated()的作用相同。用于指定函數(shù)的某個(gè)重載形式是不推薦的。當(dāng)在程序中調(diào)用了被deprecated修飾的函數(shù)時(shí),編譯器將給出C4996警告,并且可以指定具體的警告信息。該警告信息可以來源于定義的宏。 例如: // compile with: /W3 #define MY_TEXT "function is deprecated" void func1(void) {} __declspec(deprecated) void func1(int) {} __declspec(deprecated("** this is a deprecated function **")) void func2(int) {} __declspec(deprecated(MY_TEXT)) void func3(int) {} int main() { ?? func1(); ?? func1(1);?? // C4996,警告信息:warning C4996: 'func1': was declared deprecated ?? func2(1);?? // C4996,警告信息:warning C4996: 'func2': ** this is a deprecated function ** ?? func3(1);?? // C4996,警告信息:warning C4996: 'func3': function is deprecated } dllimport,dllexport: 格式: __declspec( dllimport ) declarator __declspec( dllexport ) declarator 分別用來從dll導(dǎo)入函數(shù),數(shù)據(jù),或?qū)ο笠约皬膁ll中導(dǎo)出函數(shù),數(shù)據(jù),或?qū)ο蟆O喈?dāng)于定義了dll的接口,為它的客戶exe或dll定義可使用的函數(shù),數(shù)據(jù),或?qū)ο蟆?br />將函數(shù)聲明成dllexport就可以免去定義模塊定義(.DEF)文件。 dllexport代替了__export關(guān)鍵字。 被聲明為dllexport的C++函數(shù)導(dǎo)出時(shí)的函數(shù)名將會(huì)按照C++規(guī)則經(jīng)過處理。如果要求不按照C++規(guī)則進(jìn)行名字處理,請(qǐng)使用.def文件或使用extern "C"。 jitintrinsic: 格式:__declspec(jitintrinsic) 用于標(biāo)記一個(gè)函數(shù)或元素是64位通用語(yǔ)言運(yùn)行時(shí)(CLR)。主要用于Microsoft提供的某些庫(kù)中。 使用jitintrinsic會(huì)在函數(shù)簽名中加入MODOPT(IsJitIntrinsic)。 naked: 格式:__declspec(naked) declarator 此關(guān)鍵字僅用于x86系統(tǒng),多用于虛擬設(shè)備驅(qū)動(dòng)。此關(guān)鍵字可以使編譯器在生成代碼時(shí)不包含任何注釋或標(biāo)記。僅可以對(duì)函數(shù)的定義使用,不能用于數(shù)據(jù)聲明、定義,或者函數(shù)的聲明。 noalias: 僅適用于函數(shù),它指出該函數(shù)是半純粹的函數(shù)。半純粹的函數(shù)是指僅引用或修改局部變量、參數(shù)和第一層間接參數(shù)。它是對(duì)編譯器的一個(gè)承諾,如果該函數(shù)引用全局變量或第二層間接指針參數(shù),則編譯器會(huì)生成中斷應(yīng)用程序的代碼。 restrict: 格式:__declspec(restrict) return_type f(); 僅適用于返回指針的函數(shù)聲明或定義,如,CRT的malloc函數(shù):__declspec(restrict) void *malloc(size_t size);它告訴編譯器該函數(shù)返回的指針不會(huì)與任何其它的指針混淆。它為編譯器提供執(zhí)行編譯器優(yōu)化的更多信息。對(duì)于編譯器來說,最大的困難之一是確定哪些指針會(huì)與其它指針混淆,而使用這些信息對(duì)編譯器很有幫助。有必要指出,這是對(duì)編譯器的一個(gè)承諾,編譯器并不對(duì)其進(jìn)行驗(yàn)證。如果您的程序不恰當(dāng)?shù)厥褂胈_declspec(restrict),則該程序的行為會(huì)不正確。 noinline: 因?yàn)樵陬惗x中定義的成員函數(shù)默認(rèn)都是inline的,__declspec(naked)用于顯式指定類中的某個(gè)函數(shù)不需要inline(內(nèi)聯(lián))。如果一個(gè)函數(shù)很小而且對(duì)系統(tǒng)性能影響不大,有必要將其聲明為非內(nèi)斂的。例如,用于處理錯(cuò)誤情況的函數(shù)。 noreturn: 一個(gè)函數(shù)被__declspec(noreturn)所修飾,那么它的含義是告訴編譯器,這個(gè)函數(shù)不會(huì)返回,其結(jié)果是讓編譯器知道被修飾為__declspec(noreturn)的函數(shù)之后的代碼不可到達(dá)。 如果編譯器發(fā)現(xiàn)一個(gè)函數(shù)有無返回值的代碼分支,編譯器將會(huì)報(bào)C4715警告,或者C2202錯(cuò)誤信息。如果這個(gè)代碼分支是因?yàn)楹瘮?shù)不會(huì)返回從而無法到達(dá)的話,可以使用約定__declspec(noreturn)來避免上述警告或者錯(cuò)誤。 將一個(gè)期望返回的函數(shù)約定為__declspec(noreturn)將導(dǎo)致未定義的行為。 在下面的這個(gè)例子中,main函數(shù)沒有從else分支返回,所以約定函數(shù)fatal為__declspec(noreturn)來避免編譯或警告信息。 __declspec(noreturn) extern void fatal () {} int main() { if(1) ?? return 1; else if(0) ?? return 0; else ?? fatal(); } nothrow: 格式:return-type __declspec(nothrow) [call-convention] function-name ([argument-list]) 可用于函數(shù)聲明。告訴編譯器被聲明的函數(shù)以及函數(shù)內(nèi)部調(diào)用的其它函數(shù)都不會(huì)拋出異常。 novtable: 可用于任何類聲明中,但最好只用于純接口類,即類本身從不實(shí)例化。此關(guān)鍵字的聲明將阻止編譯器對(duì)構(gòu)造和析構(gòu)函數(shù)的vfptr的初始化。可優(yōu)化編譯后代碼大小。 如果試圖實(shí)例化一個(gè)用__declspec(novtable)聲明的類然后訪問類中成員,則會(huì)在運(yùn)行時(shí)產(chǎn)生訪問錯(cuò)誤(access violation,即AV)。 process: 表示你的托管應(yīng)用程序進(jìn)程應(yīng)該擁有一份指定全局變量,靜態(tài)成員變量,或所有應(yīng)用程序域共享的靜態(tài)本地變量的拷貝。在使用/clr:pure進(jìn)行編譯時(shí),應(yīng)該使用__declspec(process),因?yàn)槭褂?clr:pure進(jìn)行編譯時(shí),在默認(rèn)情況下,每個(gè)應(yīng)用程序域擁有一份全局和靜態(tài)變量的拷貝。在使用/clr進(jìn)行編譯時(shí),不必使用__declspec(process),因?yàn)槭褂?clr進(jìn)行編譯時(shí),在默認(rèn)情況下,每個(gè)進(jìn)程有一份全局和靜態(tài)變量的拷貝。 只有全局變量,靜態(tài)成員變量,或本地類型的本地靜態(tài)變量可以用__declspec(process)修飾。 在使用/clr:pure進(jìn)行編譯時(shí),被聲明為__declspec(process)的變量同時(shí)也應(yīng)該聲明為const類型。 如果想每個(gè)應(yīng)用程序域擁有一份全局變量的拷貝時(shí),請(qǐng)使用appdomain。 property: 格式: __declspec( property( get=get_func_name ) ) declarator __declspec( property( put=put_func_name ) ) declarator __declspec( property( get=get_func_name, put=put_func_name ) ) declarator 該屬性可用于類或結(jié)構(gòu)定義中的非靜態(tài)“虛數(shù)據(jù)成員”。實(shí)際上就是做了一個(gè)映射,把你的方法映射成屬性,以供訪問。get和put就是屬性訪問的權(quán)限,一個(gè)是讀的權(quán)限,一個(gè)是寫的權(quán)限。當(dāng)編譯器看到被property修飾的數(shù)據(jù)成員出現(xiàn)在成員選擇符("." 或 "->")的右邊的時(shí)候,它將把該操作轉(zhuǎn)換成get或put方法。該修飾符也可用于類或結(jié)構(gòu)定義中的空數(shù)組。 用法如下: struct S { ?? int i; ?? void putprop(int j) { ????? i = j; ?? } ?? int getprop() { ????? return i; ?? } ?? __declspec(property(get = getprop, put = putprop)) int the_prop; }; int main() { ?? S s; ?? s.the_prop = 5; ?? return s.the_prop; } selectany: 格式:__declspec(selectany) declarator 在MFC,ATL的源代碼中充斥著__declspec(selectany)的聲明。selectany可以讓我們?cè)?h文件中初始化一個(gè)全局變量而不是只能放在.cpp中。比如有一個(gè)類,其中有一個(gè)靜態(tài)變量,那么我們可以在.h中通過類似__declspec(selectany) type class::variable = value;這樣的代碼來初始化這個(gè)全局變量。既是該.h被多次include,鏈接器也會(huì)為我們剔除多重定義的錯(cuò)誤。對(duì)于template的編程會(huì)有很多便利。 用法如下: __declspec(selectany) int x1=1; //正確,x1被初始化,并且對(duì)外部可見 const __declspec(selectany) int x2 =2; //錯(cuò)誤,在C++中,默認(rèn)情況下const為static;但在C中是正確的,其默認(rèn)情況下const不為static extern const __declspec(selectany) int x3=3; //正確,x3是extern const,對(duì)外部可見 extern const int x4; const __declspec(selectany) int x4=4; //正確,x4是extern const,對(duì)外部可見 extern __declspec(selectany) int x5; //錯(cuò)誤,x5未初始化,不能用__declspec(selectany)修飾 class X { public: X(int i){i++;}; int i; }; __declspec(selectany) X x(1); //正確,全局對(duì)象的動(dòng)態(tài)初始化 thread: 格式:__declspec(thread) declarator 聲明declarator為線程局部變量并具有線程存儲(chǔ)時(shí)限,以便鏈接器安排在創(chuàng)建線程時(shí)自動(dòng)分配的存儲(chǔ)。 線程局部存儲(chǔ)(TLS)是一種機(jī)制,在多線程運(yùn)行環(huán)境中,每個(gè)線程分配自己的局部數(shù)據(jù)。在標(biāo)準(zhǔn)多線程程序中,數(shù)據(jù)是在多個(gè)線程間共享的,而TLS是一種為每個(gè)線程分配自己局部數(shù)據(jù)的機(jī)制。 該屬性只能用于數(shù)據(jù)或不含成員函數(shù)的類的聲明和定義,不能用于函數(shù)的聲明和定義。 該屬性的使用可能會(huì)影響DLL的延遲載入。 該屬性只能用于靜態(tài)數(shù)據(jù),包括全局?jǐn)?shù)據(jù)對(duì)象(static和extern),局部靜態(tài)對(duì)象,類的靜態(tài)數(shù)據(jù)成員;不能用于自動(dòng)數(shù)據(jù)對(duì)象。 該屬性必須同時(shí)用于數(shù)據(jù)的聲明和定義,不管它的聲明和定義是在一個(gè)文件還是多個(gè)文件。 __declspec(thread)不能用作類型修飾符。 如果在類聲明的同時(shí)沒有定義對(duì)象,則__declspec(thread)將被忽略,例如: // compile with: /LD __declspec(thread) class X { public: ?? int I; } x;?? //x是線程對(duì)象 X y;?? //y不是線程對(duì)象 下面兩個(gè)例子從語(yǔ)義上來說是相同的: __declspec(thread) class B { public: ?? int data; } BObject;?? //BObject是線程對(duì)象 class B2 { public: ?? int data; }; __declspec(thread) B2 BObject2;?? // BObject2是線程對(duì)象 uuid: 格式:__declspec( uuid("ComObjectGUID") ) declarator 將具有唯一標(biāo)識(shí)符號(hào)的已注冊(cè)內(nèi)容聲明為一個(gè)變量,可使用__uuidof()調(diào)用。 用法如下: struct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown; struct __declspec(uuid("{00020400-0000-0000-c000-000000000046}")) IDispatch; |