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