您当前的位置: 首页 >  c++

Jave.Lin

暂无认证

  • 4浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C++ _cdecl,_stdcall,_fastcall 函数调用约定/协议

Jave.Lin 发布时间:2020-05-26 13:57:34 ,浏览量:4

文章目录
  • __cdecl, __stdcall, __fastcall
  • __cdecl, __stdcall 的区别
    • 函数栈帧末端处理
    • 函数出栈后处理
  • __stdcall 与 __fastcall 区别
    • 调用前
    • 调用中
  • 总结

Calling conversion,中文叫:调用约定

__cdecl, __stdcall, __fastcall

VS C++中默认的函数调用约定是__cdecl(我的VS是2019版本的,可能其他版本的不是__cdecl的),如下图: 在这里插入图片描述

如下图所示,MSVC编译器提供了四种调用约定: 在这里插入图片描述

下面是在 Debug 模式下的反汇编代码。(因为Release会优化而删减这个简单例子的代码)

__cdecl, __stdcall 的区别 函数栈帧末端处理

在这里插入图片描述 可以看到__stdcall有清理参数压栈的空间,__cdecl的没有处理清理参数压栈空间,__cdecl是在caller调用函数中清理的

函数出栈后处理

在这里插入图片描述 __cdecl在caller中清理了之前的三个push的栈空间,__stdcall就没有处理了(__stdcall在callee中清理了)

__stdcall 与 __fastcall 区别 调用前

在这里插入图片描述

从调用前,可以看到__fastcall的参数入栈方式与__stdcall的不一样

  • __fastcall 先将 int c参数压栈了
  • __stdcall 将c, b, a都压栈了

下面再看看调用中的栈帧处理

调用中

在这里插入图片描述

可以看出来,__fastcall 调用中的才将b, c直接设置栈帧内存数据,而不像__stdcall那样,在调用前就将参数push到栈帧内存数据中了。

但从这点看起来,__fastcall也没有多fast呢。。但还是加快了一点点的:后两个b, c参数都不用每个push,而是在callee函数里直接设置栈内存值。因为一个push回有stack[sp--] = value,相当于一个mov dword ptr[esp], value,然后在sub esp, 1,而__fastcall块在如果参数很多,那么就能节省掉多次的sub esp, 1

调用后的处理只是接收 eax 结果。这点__fastcall,__stdcall都一样的。(__cdecl会先清理上个栈帧的内容)

总结

__cdecl,__stdcall,__fastcall 三种方式都是从右向左将参数压栈的。 __cdecl 是在 caller 清理栈的,所以可以处理变长的参数,因为都同同一栈帧处理。 __stdcall、__fastcall 都是在 callee 清理栈的,所以不可以处理变长参数。

约定参数压栈顺序栈清理__cdecl右 -> 左caller__stdcall右 -> 左callee__fastcall右 -> 左callee
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.0395s