c++ 中__declspec 的用法詳解
c++ 中__declspec 的用法如下,想要了解的繼續(xù)往下看吧。
語法說明:
__declspec ( extended-decl-modifier-seq )
擴(kuò)展修飾符:
1:align(#)
用__declspec(align(#))精確控制用戶自定數(shù)據(jù)的對(duì)齊方式 ,#是對(duì)齊值。
e.g
__declspec(align(32)) struct Str1{ int a, b, c, d, e; };
它與#pragma pack()是一對(duì)兄弟,前者規(guī)定了對(duì)齊的最小值,后者規(guī)定了對(duì)齊的最大值。同時(shí)出現(xiàn)時(shí),前者優(yōu)先級(jí)高。
__declspec(align())的一個(gè)特點(diǎn)是,它僅僅規(guī)定了數(shù)據(jù)對(duì)齊的位置,而沒有規(guī)定數(shù)據(jù)實(shí)際占用的內(nèi)存長(zhǎng)度,當(dāng)指定的數(shù)據(jù)被放置在確定的位置之后,其后的數(shù)據(jù)填充仍然是按照#pragma pack規(guī)定的方式填充的,這時(shí)候類/結(jié)構(gòu)的實(shí)際大小和內(nèi)存格局的規(guī)則是這樣的:在__declspec(align())之前,數(shù)據(jù)按照#pragma pack規(guī)定的方式填充,如前所述。
當(dāng)遇到__declspec(align())的時(shí)候,首先尋找距離當(dāng)前偏移向后最近的對(duì)齊點(diǎn)(滿足對(duì)齊長(zhǎng)度為max(數(shù)據(jù)自身長(zhǎng)度,指定值)),然后把被指定的數(shù)據(jù)類型從這個(gè)點(diǎn)開始填充,其后的數(shù)據(jù)類型從它的后面開始,仍然按照#pragma pack填充,直到遇到下一個(gè)__declspec(align())。當(dāng)所有數(shù)據(jù)填充完畢,把結(jié)構(gòu)的整體對(duì)齊數(shù)值和__declspec(align())規(guī)定的值做比較,取其中較大的作為整個(gè)結(jié)構(gòu)的對(duì)齊長(zhǎng)度。特別的,當(dāng)__declspec(align())指定的數(shù)值比對(duì)應(yīng)類型長(zhǎng)度小的時(shí)候,這個(gè)指定不起作用。
2: allocate("segname")
用__declspec(allocate("segname")) 聲明一個(gè)已經(jīng)分配了數(shù)據(jù)段的一個(gè)數(shù)據(jù)項(xiàng)。它和#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 ) 說明一個(gè)函數(shù),類型,或別的標(biāo)識(shí)符在新的版本或未來版本中不再支持,你不應(yīng)該用這個(gè)函數(shù)或類型。它和#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接口給調(diào)用它的exe或dll文件,用 dllexport定義的函數(shù)不再需要(.def)文件聲明這些函數(shù)接口了。注意:若在dll中定義了模板類那它已經(jīng)隱式的進(jìn)行了這兩種聲明,我們只需在 調(diào)用的時(shí)候?qū)嵗纯?,呵呵?/p>
e.g 常規(guī)方式dll中
class ___declspec(dllexport) testdll{ testdll(){}; ~testdll(){}; }; 調(diào)用客戶端中聲明 #import comment(lib, "**.lib) class ___declspec(dllimportt) testdll{ testdll(){}; ~testdll(){}; };
e.g 模板類:dll中
template<class t> class test{ test(){}; ~test(){}; } 調(diào)用客戶端中聲明 int main() { test< int > b; return 0; }
5. jitintrinsic
用__declspec(jitintrinsic)標(biāo)記一個(gè)函數(shù)或元素為64位公共語言運(yùn)行時(shí)。具體用法未見到。
6. __declspec( naked )
對(duì)于沒有用naked聲明的函數(shù)一般編譯器都會(huì)產(chǎn)生保存現(xiàn)場(chǎng)(進(jìn)入函數(shù)時(shí)編譯器會(huì)產(chǎn)生代碼來保存ESI,EDI,EBX,EBP寄存器 ——prolog)和清除現(xiàn)場(chǎng)(退出函數(shù)時(shí)則產(chǎn)生代碼恢復(fù)這些寄存器的內(nèi)容——epilog) 代碼,而對(duì)于用naked聲明的函數(shù)一般不會(huì)產(chǎn)生這些代碼,這個(gè)屬性對(duì)于寫設(shè)備驅(qū)動(dòng)程序非常有用,我們自己可以寫這樣一個(gè)過程,它僅支持x86 。naked只對(duì)函數(shù)有效,而對(duì)類型定義無效。對(duì)于一個(gè)標(biāo)志了naked的函數(shù)不能產(chǎn)生一個(gè)內(nèi)聯(lián)函數(shù)即時(shí)使用了__forceinline 關(guān)鍵字。
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)用于提高程序性能,優(yōu)化程序。這兩個(gè)關(guān)鍵字都僅用于函數(shù),restrict針對(duì)于函數(shù)返回指針,restrict 說明函數(shù)返回值沒有被別名化,返回的指針是唯一的,沒有被別的函數(shù)指針別名花,也就是說返回指針還沒有被用過是唯一的。編譯器一般會(huì)去檢查指針是否可用和 是否被別名化,是否已經(jīng)在使用,使用了這個(gè)關(guān)鍵字,編譯器就不在去檢查這些信息了。noalias 意味著函數(shù)調(diào)用不能修改或引用可見的全局狀態(tài)并且僅僅修改指針參數(shù)直接指向的內(nèi)存。如果一個(gè)函數(shù)指定了noalias關(guān)鍵字,優(yōu)化器認(rèn)為除參數(shù)自生之外, 僅僅參數(shù)指針第一級(jí)間接是被引用或修改在函數(shù)內(nèi)部。可見全局狀態(tài)是指沒有定義或引用在編碼范圍外的全部數(shù)據(jù)集,它們的直至不可以取得。編碼范圍是指所有源 文件或單個(gè)源文件。其實(shí)這兩個(gè)關(guān)鍵字就是給編譯器了一種保證,編譯器信任他就不在進(jìn)行一些檢查操作了。
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)
告訴編譯器不去內(nèi)聯(lián)一個(gè)具體函數(shù)。
9. noreturn__declspec(noreturn)
告訴編譯器沒有返回值.注意添加__declspec(noreturn)到一個(gè)不希望返回的函數(shù)會(huì)導(dǎo)致已沒有定義錯(cuò)誤.
10.nothrow__declspec(nothrow)
用于函數(shù)聲明,它告訴編譯器函數(shù)不會(huì)拋出異常。
e.g
#define WINAPI __declspec(nothrow) __stdcall void WINAPI f1(); void __declspec(nothrow) __stdcall f2(); void __stdcall f3() throw();
11.novtable __declspec(novtable)
用在任意類的聲明,但是只用在純虛接口類,因此這樣的不能夠被自己實(shí)例話.它阻止編譯器初始化虛表指針在構(gòu)造和析構(gòu)類的時(shí)候,這將移除對(duì)關(guān)聯(lián)到類的虛表的 引用.如果你嘗試這實(shí)例化一個(gè)有novtable關(guān)鍵字的類,它將發(fā)生AV(access violation)錯(cuò)誤.C++里virtual的缺陷就是vtable會(huì)增大代碼的尺寸,在不需要實(shí)例化的類或者純虛接口的時(shí)候,用這個(gè)關(guān)鍵字可以減 小代碼的大小.
e.g
#if _MSC_VER >= 1100 && !defined(_DEBUG) #define AFX_NOVTABLE __declspec(novtable) #else #define AFX_NOVTABLE #endif .... class AFX_NOVTABLE CObject { ... };
這是vc里面的一段代碼,我們可以看出編譯Release版本時(shí),在CObject前是__declspec(novtable),在debug版本沒有這個(gè)限制。
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)可以讓我們?cè)?h文件中初始化一個(gè)全局變量而不是只能放在.cpp中。比如有一個(gè)類,其中有一個(gè)靜態(tài)變量,那 么我們可以在.h中通過類似" __declspec(selectany) type class::variable = value; "這樣的代碼來初始化這個(gè)全局變量。既是該.h被多次include,鏈接器也會(huì)為我們剔除多重定義的錯(cuò)誤。這個(gè)有什么好處呢,我覺得對(duì)于 teamplate的編程會(huì)有很多便利。
e.g
class test { public: static int t; }; __declspec(selectany) int test::t = 0;
13.thread
thread 用于聲明一個(gè)線程本地變量. __declspec(thread)的前綴是Microsoft添加給Visual C++編譯器的一個(gè)修改符。它告訴編譯器,對(duì)應(yīng)的變量應(yīng)該放入可執(zhí)行文件或DLL文件中它的自己的節(jié)中。__declspec(thread)后面的變量 必須聲明為函數(shù)中(或函數(shù)外)的一個(gè)全局變量或靜態(tài)變量。不能聲明一個(gè)類型為__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)
用于編譯器關(guān)聯(lián)一個(gè)GUID到一個(gè)有uuid屬性的類或結(jié)構(gòu)的聲明或者定義.
e.gstruct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;struct __declspec(uuid("{00020400-0000-0000-c000-000000000046}")) IDispatch;我們可以在MFC中查看源碼.:)
相關(guān)文章
對(duì)一個(gè)數(shù)組進(jìn)行zig-zag重新排列
本文介紹了“對(duì)一個(gè)數(shù)組進(jìn)行zig-zag重新排列”,需要的朋友可以參考一下2013-03-03減少C++代碼編譯時(shí)間的簡(jiǎn)單方法(必看篇)
下面小編就為大家?guī)硪黄獪p少C++代碼編譯時(shí)間的簡(jiǎn)單方法(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01C++中的類成員函數(shù)當(dāng)線程函數(shù)
這篇文章主要介紹了C++中的類成員函數(shù)當(dāng)線程函數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C語言中用于修改文件的存取時(shí)間的函數(shù)使用
這篇文章主要介紹了C語言中用于修改文件的存取時(shí)間的函數(shù)使用,分別為utime()函數(shù)和utimes()函數(shù)的使用,需要的朋友可以參考下2015-09-09C語言編程中對(duì)目錄進(jìn)行基本的打開關(guān)閉和讀取操作詳解
這篇文章主要介紹了C語言編程中對(duì)目錄進(jìn)行基本的打開關(guān)閉和讀取操作,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09