6

在研究使用 C++ 制作游戏的状态时,我遇到了调用约定。

在上一个问题中,有人说 MSDN 没有很好地解释 _stdcall - 我同意。

调用像 _stdcall 这样的约定的主要目的是什么?参数放在堆栈上的顺序是否重要?它如何减少 X86 中的代码大小(正如其他人所说)?

4

1 回答 1

8

一些调用约定的原因很简单:以便调用者和被调用者就事情的工作方式达成一致。没有它,调用者在调用特定函数时不知道将参数放在哪里。

至于为什么微软决定具体细节_stdcall,这在很大程度上是历史性的。在 MS-DOS 上,所有调用都是基于寄存器的,因此所有操作系统调用都需要汇编语言,或者对大多数高级语言进行奇怪的扩展。

当他们第一次做 Windows 时,他们使用cdecl调用约定,主要是因为这是编译器默认做的。至少根据谣言,在他们准备发布 Windows 1.0 之前不久,他们切换到 Pascal 调用约定,因为它足够高效,(除其他外)它允许 Windows 安装在更少的软盘上。不管具体细节如何,Pascal 调用约定确实使代码更小一些,因为被调用函数从堆栈中清除了参数,而不是在调用函数的任何地方都需要清除它们。对于从至少 2 个不同的地方调用的任何函数,这是一个胜利(如果它在其他任何地方打成平手)。

然后他们开始在 OS/2 上工作,并发明了另一种调用约定(syscall)。

然后,当然,出现了 Win32。从技术角度来看,系统调用并没有太大的问题,但是(我猜)与 OS/2 相关的所有东西都被认为是受污染的,所以系统调用必须去。结果是一些不同的东西足以证明一个新名字的合理性。公平地说,这有点夸张:他们确实添加了一个真正有用的添加:他们将参数的字节数编码到每个函数名称中,因此如果(例如)您为函数提供了不正确的原型,代码将'不链接而不是最终导致调用者和被调用者之间的不匹配,这可能导致更严重的问题。

在大多数情况下,它确实回到了最初的点:调用约定的确切细节并不重要,只要你不把它弄得一团糟。最重要的是调用者和被调用者在同一件事上达成一致,因此如果编译器知道函数接受哪些参数,它就知道如何生成代码以正确地将这些参数传递给函数(同样,它们都同意如何处理堆栈清理等)

于 2012-12-01T23:31:06.363 回答