__cdecl与__stdcall概念中的调用者和被调用者是什么意思?

我只学过C入门,只做过课后习题,最近刚学windows下的C。
但书上第一个程序我就看不懂了

int WINAPI WinMain()

这里的WINAPI我从来没见过这种用法,网上查了下其实是指定__cdecl或__stdcall等这样的函数调用约定,但即使是看了大篇文章后我还是不懂,主要是这些话:

不论__stdcall还是__cdecl函数参数都是从右向左入栈的,并且由调用者完成入栈操作。对于__stdcall方式被调用者自身在函数返回前清空堆栈;而__cdecl则由调用者维护内存堆栈,所以调用者函数生成的汇编代码比前一种方式长。

我想知道上述的调用者/被调用者是人(我自己)还是函数?这些入栈/清空堆栈的操作指的是不是要在申请动态内存后要记得free()掉?不然指的是什么?

阅读 6.2k
3 个回答

你都已经查到 __stdcall这一步了,再往下多查一步不就知道了么。

调用者(caller)和被调用者(callee)都是指函数。入栈清栈指的是函数调用参数传递的方式。清栈职责在caller这边,意思就是:

cfoo(123);

转换成汇编是:

gaspush 123;
call foo;
add $4,%esp;  #将Stack Pointer %esp 加4即是清栈
              #4表示32位下4个字节一个word

如果职责在callee那边,上面最后一行就移到foo中:

gasfoo:
  # do something
  add $4,%esp
  ret

后一种方式一个函数只能接受固定个数的参数,因为编译时就需要确定 add x,%espx到底是几。

哦,对了,这些都是编译器的行为,程序员根本不需要关心。

学编程最重要的是了解运行环境、如操作系统、编译器。语言本身并不太重要。
有一个必需掌握的能力就是调试能力,要有汇编级调试能力。有了这个能力,你的问题调试跟踪一下能找到答案了。
很多时候,要提高这种能力,可以通过学习逆向工程获得。
国内看雪学院http://www.pediy.com/是个不错的地方。

WINAPI本身就宏定义,也就是 #define WINAPI __stdcall 当然这个在Mac下面不一样。几乎所有的Win32 API函数都是这种类型。编译后的程序体积小些,名字改编不一样。还有一个明显的特征,比如printf支持变长,而WINAPI的是不支持变长的,因为被调用者不知道传入参数是多少,不懂的如何去清理,所以这里printf得是__cdecl

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进