__declspec關鍵字詳細用法

原文鏈接:http://hi.baidu.com/baiyw920/blog/item/a06ddb986314fd0f6e068c0c.html

       __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是對齊參數,其有效值是的整數次冪(從到字節),如,,,,或。參數declarator是要設置對齊方式的數據。

1.使用__declspec(align(n))來精確控制用戶自定義數據的對齊方式。你可以在定義struct,union,class或聲明變量時使用__declspec(align(n))。

2.不能爲函數參數使用__declspec(align(n))。

3.如果未使用__declspec(align(#)),編譯器將根據數據大小按自然邊界對齊。如字節整數按字節邊界對齊;字節double按字節邊界對齊。類或結構體中的數據,將取數據本身的自然對齊方式和#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)

用於標記一個函數或元素是位通用語言運行時(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的初始化。可優化編譯後代碼大小。

如果試圖實例化一個用__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;

發佈了16 篇原創文章 · 獲贊 16 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章