不知道函数怎么运行的, 所以堆栈怎么产生也不太明白, 堆栈如何产生的
// ? 这个函数有什么堆栈
void func()
{
}
// ? 这个函数堆栈又是什么样,在函数退出时,堆栈怎么办
void func()
{
int a = 0 ; // 定义了一个变量, 这个变量保存在堆栈中吗
printf("%d" , a );
}
// ? 这个函数会不会有堆栈,怎么样
void func()
{
char *p = (char * ) malloc( sizeof(char)) ;
free(p);
}
15 个解决方案
#1
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx
#2
_stdcall与_cdecl的作用 关于堆栈
两种函数的局部变量是一样的, 关键是参数使用栈不一样而已
_stdcall 在函数内部释放栈
如汇编代码: __asm ret 4;
_cdecl 需要调用函数的对象释放栈
如汇编代码: __asm add esp, 4
两种函数的局部变量是一样的, 关键是参数使用栈不一样而已
_stdcall 在函数内部释放栈
如汇编代码: __asm ret 4;
_cdecl 需要调用函数的对象释放栈
如汇编代码: __asm add esp, 4
#3
http://blog.csdn.net/na_he/archive/2008/05/07/2408655.aspx
__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。
__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。
#4
传输传递用到
就是堆栈的平衡问题
就是堆栈的平衡问题
#5
只有清栈的时候有区别
因此,stdcall不支持可变参数
因此,stdcall不支持可变参数
#6
_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同
这个我明白,我想知道,堆栈是如何产生的
#7
如果LZ确实要把堆栈弄的很清楚,那么就要从汇编说起...
#8
stdcall与cdecl都是通过栈来传递参数,在调用函数时,从最右边的参数开始,依次向左逐个push到栈中,最后call函数地址,函数中根据刚刚进入函数时esp的值来访问这些参数,stdcall方式是在函数返回时利用ret指令清除栈中的参数,cdecl方式是函数返回后,由调用函数者修改esp的值来清除栈中的参数。
#9
要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?
#10
这个是不是涉及到了编译原理,没学过这个,所以对椎栈也就不懂了
#11
不学编译原理也没关系,但需要懂汇编。
#12
// ? 这个函数有什么堆栈
->栈中有函数的返回地址和EBP
void func()
{
}
// ? 这个函数堆栈又是什么样,在函数退出时,堆栈怎么办
->栈中有函数的返回地址、EBP和局部变量a,函数退出根据调用的方式,决定有哪个清理栈。
void func()
{
int a = 0 ; // 定义了一个变量, 这个变量保存在堆栈中吗
printf("%d" , a );
}
// ? 这个函数会不会有堆栈,怎么样
-> 当然有栈里的内容是:函数的返回地址,EBP和指针p本身的地址。
void func()
{
char *p = (char * ) malloc( sizeof(char)) ;
free(p);
}
->栈中有函数的返回地址和EBP
void func()
{
}
// ? 这个函数堆栈又是什么样,在函数退出时,堆栈怎么办
->栈中有函数的返回地址、EBP和局部变量a,函数退出根据调用的方式,决定有哪个清理栈。
void func()
{
int a = 0 ; // 定义了一个变量, 这个变量保存在堆栈中吗
printf("%d" , a );
}
// ? 这个函数会不会有堆栈,怎么样
-> 当然有栈里的内容是:函数的返回地址,EBP和指针p本身的地址。
void func()
{
char *p = (char * ) malloc( sizeof(char)) ;
free(p);
}
#13
_cdecl为了支持可变参数而使用.
被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大
被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大
#14
学习了...
#15
板凳
#1
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx
#2
_stdcall与_cdecl的作用 关于堆栈
两种函数的局部变量是一样的, 关键是参数使用栈不一样而已
_stdcall 在函数内部释放栈
如汇编代码: __asm ret 4;
_cdecl 需要调用函数的对象释放栈
如汇编代码: __asm add esp, 4
两种函数的局部变量是一样的, 关键是参数使用栈不一样而已
_stdcall 在函数内部释放栈
如汇编代码: __asm ret 4;
_cdecl 需要调用函数的对象释放栈
如汇编代码: __asm add esp, 4
#3
http://blog.csdn.net/na_he/archive/2008/05/07/2408655.aspx
__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。
__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。
#4
传输传递用到
就是堆栈的平衡问题
就是堆栈的平衡问题
#5
只有清栈的时候有区别
因此,stdcall不支持可变参数
因此,stdcall不支持可变参数
#6
_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同
这个我明白,我想知道,堆栈是如何产生的
#7
如果LZ确实要把堆栈弄的很清楚,那么就要从汇编说起...
#8
stdcall与cdecl都是通过栈来传递参数,在调用函数时,从最右边的参数开始,依次向左逐个push到栈中,最后call函数地址,函数中根据刚刚进入函数时esp的值来访问这些参数,stdcall方式是在函数返回时利用ret指令清除栈中的参数,cdecl方式是函数返回后,由调用函数者修改esp的值来清除栈中的参数。
#9
要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?
#10
这个是不是涉及到了编译原理,没学过这个,所以对椎栈也就不懂了
#11
不学编译原理也没关系,但需要懂汇编。
#12
// ? 这个函数有什么堆栈
->栈中有函数的返回地址和EBP
void func()
{
}
// ? 这个函数堆栈又是什么样,在函数退出时,堆栈怎么办
->栈中有函数的返回地址、EBP和局部变量a,函数退出根据调用的方式,决定有哪个清理栈。
void func()
{
int a = 0 ; // 定义了一个变量, 这个变量保存在堆栈中吗
printf("%d" , a );
}
// ? 这个函数会不会有堆栈,怎么样
-> 当然有栈里的内容是:函数的返回地址,EBP和指针p本身的地址。
void func()
{
char *p = (char * ) malloc( sizeof(char)) ;
free(p);
}
->栈中有函数的返回地址和EBP
void func()
{
}
// ? 这个函数堆栈又是什么样,在函数退出时,堆栈怎么办
->栈中有函数的返回地址、EBP和局部变量a,函数退出根据调用的方式,决定有哪个清理栈。
void func()
{
int a = 0 ; // 定义了一个变量, 这个变量保存在堆栈中吗
printf("%d" , a );
}
// ? 这个函数会不会有堆栈,怎么样
-> 当然有栈里的内容是:函数的返回地址,EBP和指针p本身的地址。
void func()
{
char *p = (char * ) malloc( sizeof(char)) ;
free(p);
}
#13
_cdecl为了支持可变参数而使用.
被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大
被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大
#14
学习了...
#15
板凳