1. 程式人生 > >__declspec用法

__declspec用法

原文連結:https://blog.csdn.net/zhangzq86/article/details/52982939

          修飾函式  關鍵字

                __declspec用於指定所給定型別的例項的與Microsoft相關的儲存方式。其它的有關儲存方式的修飾符如static與extern等是C和 C++語言的ANSI規範,而__declspec是一種擴充套件屬性的定義。擴充套件屬性語法簡化並標準化了C和C++語言關於Microsoft的擴充套件。

用法:__declspec ( extended-decl-modifier )
extended-decl-modifier引數如下,可同時出現,中間有空格隔開:
align (C++)  __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的初始化。可優化編譯後代碼大小。
如果試圖例項化一個用__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;