__stdcall和__cdecl的区别
__stdcall和__cdecl是兩種函數(shù)名字修飾。(注意是連續(xù)的兩個(gè)下劃線)
Windows上
windows上不管是C還是C++,默認(rèn)使用的都是__stdcall方式。
不論__stdcall還是__cdecl函數(shù)參數(shù)都是從可向左入棧的,并且由調(diào)用者完成入棧操作。對于__stdcall方式被調(diào)用者自身在函數(shù)返回前清空堆棧;而__cdecl則由調(diào)用者維護(hù)內(nèi)存堆棧,所以調(diào)用者函數(shù)生成的匯編代碼比前一種方式長。
由__cdecl約定的函數(shù)只能被C/C++調(diào)用。
Windows上使用dumpbin工具查看函數(shù)名字修飾。
C語言
__stdcall方式:_FuncName@sizeofParameters
例如:int __stdcall test(int a,double b)編譯之后完整的函數(shù)名為_test@12
__cdecl方式:_FuncName
例如:int __stdcall test(int a,double b)編譯之后完整的函數(shù)名為_test
由于C++允許重載函數(shù),所以函數(shù)的名字修飾就不能像C這么簡單,C++中的函數(shù)名字修飾應(yīng)該包含返回類型,各參數(shù)類型等信息,如果是類成員函數(shù),還應(yīng)該包含類名、訪問級別、是否為const函數(shù)等等信息。
C++語言
不管__cdecl,__fastcall還是__stdcall調(diào)用方式,函數(shù)修飾都是以一個(gè)“?”開始,后面緊跟函數(shù)的名字,再后面是參數(shù)表的開始標(biāo)識和按照參數(shù)類型代號拼出的參數(shù)表。對于__stdcall方式,參數(shù)表的開始標(biāo)識是“@@YG”,對于__cdecl方式則是“@@YA”。
X--void????
D--char????
E--unsigned char????
F--short????
H--int????
I--unsigned int????
J--long????
K--unsigned long(DWORD)?
M--float????
N--double????
_N--bool
U--struct
PA--指針
PB--const類型的指針
如果相同類型的指針連續(xù)出現(xiàn),以“0”代替,一個(gè)“0”代表一次重復(fù);
U表示結(jié)構(gòu)類型,通常后跟結(jié)構(gòu)體的類型名,用“@@”表示結(jié)構(gòu)類型名的結(jié)束;
函數(shù)參數(shù)表的第一項(xiàng)實(shí)際上是表示函數(shù)的返回值類型;
參數(shù)表后以“@Z”標(biāo)識整個(gè)名字的結(jié)束,如果該函數(shù)無參數(shù),則以“Z”標(biāo)識結(jié)束。
舉例:
int Function1 (char *var1,unsigned long);其函數(shù)修飾名為“?Function1@@YGHPADK@Z”
void Function2();其函數(shù)修飾名則為“?Function2@@YGXXZ”?
C++中調(diào)用由C編譯器生成的函數(shù)
extern "C" {
long func(int a);
char* strcat(char*,const char*);
}
extern "C" {
#include<string.h>
}
要想在編譯階段就知道使用的編譯器類型,可以使用:
| #ifdef __cplusplus cout<<"C++"; #else printf("C"); #endif |
通常應(yīng)該這樣聲明頭文件:
| #ifdef _cplusplus extern?"C"?{ #endif long?MakeFun(long?lFun); #ifdef _cplusplus } #endif |
?有兩種方式可以檢查你的程序中的函數(shù)的名字修飾:使用編譯輸出列表或使用Dumpbin工具。使用/FAc,/FAs或/FAcs命令行參數(shù)可以讓編譯器輸出函數(shù)或變量名字列表。使用dumpbin.exe /SYMBOLS命令也可以獲得obj文件或lib文件中的函數(shù)或變量名字列表。此外,還可以使用 undname.exe 將修飾名轉(zhuǎn)換為未修飾形式。
Linux上
Linux上使用__stdcall和__cdecl的方式比較麻煩一些。
| int?__attribute__((cdecl)) test(); |
Linux上使用nm工具查看函數(shù)名字修飾。
__stdcall和__cdecl沒有區(qū)別,有區(qū)別的是編程語言。
C++語言
char test(); ?----- ? ?_Z4testv ? ? ? ? ? ?_Z表示C++,4代表函數(shù)名有4個(gè)字節(jié),test是函數(shù)名,v代表參數(shù)為空
double func(unsigned int a,double *b,char c); ? ----- ? ? ?_Z4funcjPdc ? ? j代表int,Pd代表double型指針,c代表char
C語言
只是簡單一個(gè)函數(shù)名,沒有其他修飾信息。
char test(); ?----- ? ?test
double func(unsigned int a,double *b,char c); ? ----- ? ? ?func
?
附:
Linux上的反匯編工具:objdump ?-x ?exefile
查看二進(jìn)制文件:hexdump -C biFile
編輯二進(jìn)制文件:hexedit biFile
總結(jié)
以上是生活随笔為你收集整理的__stdcall和__cdecl的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 函数调用方式__stdecl _stdc
- 下一篇: vector的reserve和resiz