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。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)