_stdcall与_cdecl的作用,是说明如何清空堆栈. 那堆栈里有哪些数据呢,什么时候会用到堆栈

时间:2021-05-04 16:01:00
还是不太明白这两个函数的区别, 一个是调用者清空堆栈, 可变参数, 一个是被调用者清空堆栈,不可变参数

不知道函数怎么运行的, 所以堆栈怎么产生也不太明白, 堆栈如何产生的


// ? 这个函数有什么堆栈
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

#2


_stdcall与_cdecl的作用 关于堆栈

两种函数的局部变量是一样的, 关键是参数使用栈不一样而已

_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缺省调用约定。

#4


传输传递用到
就是堆栈的平衡问题

#5


只有清栈的时候有区别
因此,stdcall不支持可变参数

#6


引用 1 楼 zhoujianhei 的回复:
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。 
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx



_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同

这个我明白,我想知道,堆栈是如何产生的

#7


引用 6 楼 liangzhonglin 的回复:
引用 1 楼 zhoujianhei 的回复:
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。 
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx 
 


_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同 

这个我明白,我想知道,堆栈是如何产…


如果LZ确实要把堆栈弄的很清楚,那么就要从汇编说起...

#8


stdcall与cdecl都是通过栈来传递参数,在调用函数时,从最右边的参数开始,依次向左逐个push到栈中,最后call函数地址,函数中根据刚刚进入函数时esp的值来访问这些参数,stdcall方式是在函数返回时利用ret指令清除栈中的参数,cdecl方式是函数返回后,由调用函数者修改esp的值来清除栈中的参数。

#9


要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?

#10


引用 9 楼 Mackz 的回复:
要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?


这个是不是涉及到了编译原理,没学过这个,所以对椎栈也就不懂了

#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);
}

#13


_cdecl为了支持可变参数而使用.

被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大

#14


学习了...

#15


板凳

#1


_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx

#2


_stdcall与_cdecl的作用 关于堆栈

两种函数的局部变量是一样的, 关键是参数使用栈不一样而已

_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缺省调用约定。

#4


传输传递用到
就是堆栈的平衡问题

#5


只有清栈的时候有区别
因此,stdcall不支持可变参数

#6


引用 1 楼 zhoujianhei 的回复:
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。 
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx



_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同

这个我明白,我想知道,堆栈是如何产生的

#7


引用 6 楼 liangzhonglin 的回复:
引用 1 楼 zhoujianhei 的回复:
_stdcall与_cdecl的作用,只对函数带有参数起作用,与函数内部变量无关,虽然内部变量也在栈中,但释放的时候是由函数在返回之前进行的。 
http://blog.csdn.net/zhoujianhei/archive/2008/03/12/2172964.aspx 
 


_stdcall与_cdecl只是对于不同的编译器而言的, 如果都是用VC写的,就不需要关心, 如果用VC调用DELPHI写的DLL, 就需要关心,因为编译器不同 

这个我明白,我想知道,堆栈是如何产…


如果LZ确实要把堆栈弄的很清楚,那么就要从汇编说起...

#8


stdcall与cdecl都是通过栈来传递参数,在调用函数时,从最右边的参数开始,依次向左逐个push到栈中,最后call函数地址,函数中根据刚刚进入函数时esp的值来访问这些参数,stdcall方式是在函数返回时利用ret指令清除栈中的参数,cdecl方式是函数返回后,由调用函数者修改esp的值来清除栈中的参数。

#9


要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?

#10


引用 9 楼 Mackz 的回复:
要明白堆栈,必须先学汇编,搞清楚在汇编中是如何调用函数、如何参数入栈、返回值出栈、堆栈平衡。没有这些概念,怎么跟你解释得清楚?


这个是不是涉及到了编译原理,没学过这个,所以对椎栈也就不懂了

#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);
}

#13


_cdecl为了支持可变参数而使用.

被调用者不知道有多少个参数近来了,没法add esp,参数个数 *4
只好让调用者负责,这导致生成的EXE的文件稍大

#14


学习了...

#15


板凳