__declspec關鍵字詳細用法

__declspec用於指定所給定類型的實例的與Microsoft相關的存儲方式。其它的有關存儲方式的修飾符如staticextern等是CC++語言的ANSI規範,而__declspec是一種擴展屬性的定義。擴展屬性語法簡化並標準化了CC++語言關於Microsoft的擴展。 編程

用法:__declspec ( extended-decl-modifier ) 數組

extended-decl-modifier參數以下,可同時出現,中間有空格隔開: 多線程

align (C++ app

allocate dom

appdomain 函數

deprecated (C++ 性能

dllimport 優化

dllexport ui

jitintrinsic this

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))來精確控制用戶自定義數據的對齊方式。你能夠在定義structunionclass或聲明變量時使用__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的接口,爲它的客戶exedll定義可以使用的函數,數據,或對象。

將函數聲明成dllexport就能夠免去定義模塊定義(.DEF)文件。

dllexport代替了__export關鍵字。

被聲明爲dllexportC++函數導出時的函數名將會按照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();

僅適用於返回指針的函數聲明或定義,如,CRTmalloc函數:__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

該屬性可用於類或結構定義中的非靜態「虛數據成員」。實際上就是作了一個映射,把你的方法映射成屬性,以供訪問。getput就是屬性訪問的權限,一個是讀的權限,一個是寫的權限。當編譯器看到被property修飾的數據成員出如今成員選擇符("." 或"->")的右邊的時候,它將把該操做轉換成getput方法。該修飾符也可用於類或結構定義中的空數組。

用法以下:

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

MFCATL的源代碼中充斥着__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++中,默認狀況下conststatic;但在C中是正確的,其默認狀況下const不爲static

extern const __declspec(selectany) int x3=3; //正確,x3extern const,對外部可見

extern const int x4;

const __declspec(selectany) int x4=4; //正確,x4extern 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的延遲載入。

該屬性只能用於靜態數據,包括全局數據對象(staticextern),局部靜態對象,類的靜態數據成員;不能用於自動數據對象。

該屬性必須同時用於數據的聲明和定義,無論它的聲明和定義是在一個文件仍是多個文件。

__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;

相關文章
相關標籤/搜索