“_cdecl”和“__cdecl”的区别是什么?

“_cdecl”和“__cdecl”的区别是什么?,第1张

1、_cdecl c调用约定, 按从右至左的顺序压参数入栈,由调用者把参数d出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。

另外,在函数名修饰约定方面也有所不同。 _cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀,是MFC缺省调用约定。

2、__cdecl是C/C++和MFC程序默认使用的调用约定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数d出栈以清理堆栈。

因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。

__declspec一般是ms对标准c++语言的扩充指令.经典的象dllexport,property(get=...)等等.不想跨平台用用不错.

__cdecl,__stdcall是声明的函数调用协议.主要是传参和d栈方面的不同.一般c++用的是__cdecl,windows里大都用的是__stdcall(API)

函数调用规范__cdecl和__stdcall的区别一目了然(表格形式) 转载- -

Tag: __cdecl__stdcall区别

__cdecl

__stdcall

C和C++程序的缺省调用规范

为了使用这种调用规范,需要你明确的加上__stdcall(或WINAPI)文字。即return-type__stdcallfunction-name[(argument-list)]

在被调用函数(Callee)返回后,由调用者(Caller)调整堆栈。

调用者

// call function

// adjust stack

被调用函数

// do work

// return

在被调用函数(Callee)返回前,由被调用函数(Callee)调整堆栈。图示:

调用者

// call function

被调用函数

// do work

// adjust stack

// return

因为每个调用的地方都需要生成一段调整堆栈的代码,所以最后生成的文件较大。

因为调整堆栈的代码只存在在一个地方(被调用函数的代码内),所以最后生成的文件较小。

函数的参数个数可变(就像printf函数一样),因为只有调用者才知道它传给被调用函数几个参数,才能在调用结束时适当地调整堆栈。

函数的参数个数不能是可变的。

对于定义在C程序文件中的输出函数,函数名会保持原样,不会被修饰。

对于定义在C++程序文件中的输出函数,函数名会被修饰, MSDN说Underscore character (_) is prefixed to names. 我实际测试(VC4和VC6)下来发现好像不是那么简单。

可通过在前面加上extern “C”以去除函数名修饰。也可通过.def文件去除函数名修饰。

不论是C程序文件中的输出函数还是C++程序文件中的输出函数,函数名都会被修饰。

对于定义在C程序文件中的输出函数,An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.

对于定义在C++程序文件中的输出函数,好像更复杂,和__cdecl的情况类似。

好像只能通过.def文件去除函数名修饰。

_beginthread需要__cdecl的线程函数地址

_beginthreadex和CreateThread需要__stdcall的线程函数地址

指针数组是一种特殊的数组,指针数组的数组元素都是指针变量。指针数组的定义格式为:

类型名称 *数组名称[数组长度]

例如:float *pf[3]

因为下标运算符[]的优先级高于指针运算符*,上述定义等价于:float * (pf[3])

说明pf是一个含有3个元素的数组,数组元素为指向float型变量的指针变量。

又如:

int *pn[5]/*定义一个5个元素的指针数组,数组元素为指向int型变量的指针变量*/

char *pc[10]/*定义一个10个元素的指针数组,元素为指向char型变量的指针变量*/

不论指针数组是什么类型,指针数组的每个数组元素都用来保存一个地址值,在TurboC下,每个数组元素是一个unsigned int型变量,占用2个字节。

指针数组定义后,可以使数组元素指向一个变量和其他数组的首地址。下面是一个指针数组定义和引用的例子。

main()

{

int i

char c1[]="How"

char c2[]="are"

char *c3="you"

char *pArray[3]

pArray[0]=c1

pArray[1]=c2

pArray[2]=c3

for(i=0i<3i++)

printf("%s ", pArray[i])

}

程序运行的结果为:

How are you

说明:

(1)程序中c1,c2被定义为字符数组并初始化;c3是一个指针变量,指向字符串所在字符数组的首地址。

(2)语句char *pArray[3]定义了三个元素的指针数组pArray,数组元素是指向char型变量或数组的指针变量。

(3)语句pArray[0]=c1将字符数组c1的首地址赋给pArray[0],指针变量pArray[0]指向了c1的首地址。

(4)for循环中,语句printf("%s ", pArray[i])依次打印了三个字符数组的内容。比如,pArray[0]里存放了c1的首地址,printf("%s ", pArray[0])和printf("%s ", c1)的作用是相同的。

字符数组c1,c2,c3和指针数组pArray的内存情况如下图(图中的数组首地址值是假设的值)。

指针数组pArray占用了从FFC0开始的6个字节。char型变量占用1个字节,因此字符数组c1,c2,c3均占用4个字节(包括字符串结束符'\0')。pArray[0]里存放了字符数组c1的首地址FF10,使pArray[0]指向c1。pArray[1]里存放了字符数组c2的首地址FF50,使pArray[1]指向c2。pArray[2]里存放了字符数组c3的首地址FF70,使pArray[2]指向c3。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11222726.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-14
下一篇 2023-05-14

发表评论

登录后才能评论

评论列表(0条)

保存