c++ 中__declspec 的用法詳解。本站提示廣大學習愛好者:(c++ 中__declspec 的用法詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是c++ 中__declspec 的用法詳解正文
c++ 中__declspec 的用法如下,想要理解的持續往下看吧。
語法闡明:
__declspec ( extended-decl-modifier-seq )
擴展修飾符:
1:align(#)
用__declspec(align(#))准確控制用戶自定數據的對齊方式 ,#是對齊值。
e.g
__declspec(align(32)) struct Str1{ int a, b, c, d, e; };
它與#pragma pack()是一對兄弟,前者規則了對齊的最小值,後者規則了對齊的最大值。同時呈現時,前者優先級高。
__declspec(align())的一個特點是,它僅僅規則了數據對齊的地位,而沒有規則數據實踐占用的內存長度,當指定的數據被放置在確定的地位之後,其後的數據填充依然是依照#pragma pack規則的方式填充的,這時分類/構造的實踐大小和內存格式的規則是這樣的:在__declspec(align())之前,數據依照#pragma pack規則的方式填充,如前所述。
當遇到__declspec(align())的時分,首先尋覓間隔以後偏移向後最近的對齊點(滿足對齊長度為max(數據本身長度,指定值)),然後把被指定的數據類型從這個點開端填充,其後的數據類型從它的前面開端,依然依照#pragma pack填充,直到遇到下一個__declspec(align())。當一切數據填充終了,把構造的全體對齊數值和__declspec(align())規則的值做比擬,取其中較大的作為整個構造的對齊長度。特別的,當__declspec(align())指定的數值比對應類型長度小的時分,這個指定不起作用。
2: allocate("segname")
用__declspec(allocate("segname")) 聲明一個曾經分配了數據段的一個數據項。它和#pragma 的code_seg, const_seg, data_seg,section,init_seg配合運用,segname必需有這些東東聲明。
e.g
#pragma data_seg("share_data") int a = 0; int b; #pragma data_seg() __declspec(allocate("share_data")) int c = 1; __declspec(allocate("share_data")) int d;
3. deprecated
用__declspec(deprecated ) 闡明一個函數,類型,或別的標識符在新的版本或將來版本中不再支持,你不應該用這個函數或類型。它和#pragma deprecated作用一樣。
e.g
#define MY_TEXT "function is deprecated" void func1(void) {} __declspec(deprecated) void func1(int) { printf("func1n");} __declspec(deprecated("** this is a deprecated function **")) void func2(int) { printf("func2n");} __declspec(deprecated(MY_TEXT)) void func3(int) { printf("func3");} int main() { fun1(); fun2(); fun3(); }
4.dllimport 和dllexport
用__declspec(dllexport),__declspec(dllimport)顯式的定義dll接口給調用它的exe或dll文件,用 dllexport定義的函數不再需求(.def)文件聲明這些函數接口了。留意:若在dll中定義了模板類那它曾經隱式的停止了這兩種聲明,我們只需在 調用的時分實例化即可,呵呵。
e.g 慣例方式dll中
class ___declspec(dllexport) testdll{ testdll(){}; ~testdll(){}; }; 調用客戶端中聲明 #import comment(lib, "**.lib) class ___declspec(dllimportt) testdll{ testdll(){}; ~testdll(){}; };
e.g 模板類:dll中
template<class t> class test{ test(){}; ~test(){}; } 調用客戶端中聲明 int main() { test< int > b; return 0; }
5. jitintrinsic
用__declspec(jitintrinsic)標志一個函數或元素為64位公共言語運轉時。詳細用法未見到。
6. __declspec( naked )
關於沒有用naked聲明的函數普通編譯器都會發生保管現場(進入函數時編譯器會發生代碼來保管ESI,EDI,EBX,EBP存放器 ——prolog)和肅清現場(加入函數時則發生代碼恢復這些存放器的內容——epilog) 代碼,而關於用naked聲明的函數普通不會發生這些代碼,這個屬性關於寫設備驅動順序十分有用,我們自己可以寫這樣一個進程,它僅支持x86 。naked只對函數無效,而對類型定義有效。關於一個標志了naked的函數不能發生一個內聯函數即時運用了__forceinline 關鍵字。
e.g
__declspec ( naked ) func() { int i; int j; __asm /* prolog */ { push ebp mov ebp, esp sub esp, __LOCAL_SIZE } /* Function body */ __asm /* epilog */ { mov esp, ebp pop ebp ret } }
7. restrict 和 noalias
__declspec(restrict) 和 __declspec(noalias)用於進步順序功能,優化順序。這兩個關鍵字都僅用於函數,restrict針關於函數前往指針,restrict 闡明函數前往值沒有被別名化,前往的指針是獨一的,沒有被別的函數指針別名花,也就是說前往指針還沒有被用過是獨一的。編譯器普通會去反省指針能否可用和 能否被別名化,能否曾經在運用,運用了這個關鍵字,編譯器就不在去反省這些信息了。noalias 意味著函數調用不能修正或援用可見的全局形態並且僅僅修正指針參數直接指向的內存。假如一個函數指定了noalias關鍵字,優化器以為除參數自生之外, 僅僅參數指針第一級直接是被援用或修正在函數外部。可見全局形態是指沒有定義或援用在編碼范圍外的全部數據集,它們的直至不可以獲得。編碼范圍是指一切源 文件或單個源文件。其實這兩個關鍵字就是給編譯器了一種保證,編譯器信任他就不在停止一些反省操作了。
e.g
#include <stdio.h> #include <stdlib.h> #define M 800#define N 600#define P 700float * mempool, * memptr; __declspec(restrict) float * ma(int size) { float * retval; retval = memptr; memptr += size; return retval; } __declspec(restrict) float * init(int m, int n) { float * a; int i, j; int k=1; a = ma(m * n); if (!a) exit(1); for (i=0; i<m; i++) for (j=0; j<n; j++) a[i*n+j] = 0.1/k++; return a; } __declspec(noalias) void multiply(float * a, float * b, float * c) { int i, j, k; for (j=0; j<P; j++) for (i=0; i<M; i++) for (k=0; k<N; k++) c[i * P + j] = a[i * N + k] * b[k * P + j]; } int main() { float * a, * b, * c; mempool = (float *) malloc(sizeof(float) * (M*N + N*P + M*P)); if (!mempool) puts("ERROR: Malloc returned null"); exit(1); memptr = mempool; a = init(M, N); b = init(N, P); c = init(M, P); multiply(a, b, c); }
8. noinline__declspec(noinline)
通知編譯器不去內聯一個詳細函數。
9. noreturn__declspec(noreturn)
通知編譯器沒有前往值.留意添加__declspec(noreturn)到一個不希望前往的函數會招致已沒有定義錯誤.
10.nothrow__declspec(nothrow)
用於函數聲明,它通知編譯器函數不會拋出異常。
e.g
#define WINAPI __declspec(nothrow) __stdcall void WINAPI f1(); void __declspec(nothrow) __stdcall f2(); void __stdcall f3() throw();
11.novtable __declspec(novtable)
用在恣意類的聲明,但是只用在純虛接口類,因而這樣的不可以被自己實例話.它阻止編譯器初始化虛表指針在結構和析構類的時分,這將移除對關聯到類的虛表的 援用.假如你嘗試這實例化一個有novtable關鍵字的類,它將發作AV(access violation)錯誤.C++裡virtual的缺陷就是vtable會增大代碼的尺寸,在不需求實例化的類或許純虛接口的時分,用這個關鍵字可以減 小代碼的大小.
e.g
#if _MSC_VER >= 1100 && !defined(_DEBUG) #define AFX_NOVTABLE __declspec(novtable) #else #define AFX_NOVTABLE #endif .... class AFX_NOVTABLE CObject { ... };
這是vc外面的一段代碼,我們可以看出編譯Release版本時,在CObject前是__declspec(novtable),在debug版本沒有這個限制。
e.g
#include <stdio.h> struct __declspec(novtable) X { virtual void mf(); }; struct Y : public X { void mf() { printf_s("In Yn"); } };
12.selectany的作用
__declspec(selectany)可以讓我們在.h文件中初始化一個全局變量而不是只能放在.cpp中。比方有一個類,其中有一個靜態變量,那 麼我們可以在.h中經過相似" __declspec(selectany) type class::variable = value; "這樣的代碼來初始化這個全局變量。既是該.h被屢次include,鏈接器也會為我們剔除多重定義的錯誤。這個有什麼益處呢,我覺得關於 teamplate的編程會有很多便當。
e.g
class test { public: static int t; }; __declspec(selectany) int test::t = 0;
13.thread
thread 用於聲明一個線程本地變量. __declspec(thread)的前綴是Microsoft添加給Visual C++編譯器的一個修正符。它通知編譯器,對應的變量應該放入可執行文件或DLL文件中它的自己的節中。__declspec(thread)前面的變量 必需聲明為函數中(或函數外)的一個全局變量或靜態變量。不能聲明一個類型為__declspec(thread)的部分變量。
e.g
__declspec(thread) class X{ public: int I; } x; // x is a thread objectX y; // y is not a thread object
14.uuid__declspec(uuid)
用於編譯器關聯一個GUID到一個有uuid屬性的類或構造的聲明或許定義.
e.gstruct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;struct __declspec(uuid("{00020400-0000-0000-c000-000000000046}")) IDispatch;我們可以在MFC中檢查源碼.:)