简单明了,我们为什么要使用_stdcall

Plainly and simply, why do we use _stdcall?

本文关键字:stdcall 为什么 我们 简单      更新时间:2023-10-16

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

在之前的一个问题中,有人说MSDN没有很好地解释_stdcall——我同意。

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

使用一些调用约定的原因非常简单:这样调用者和被调用者就可以就如何工作达成一致。如果没有它,调用方在调用特定函数时不知道将参数放在哪里。

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

当他们第一次使用Windows时,他们使用了cdecl调用约定,主要是因为编译器默认是这样做的。至少有传言称,在他们准备发布Windows1.0之前不久,他们改用了Pascal调用约定,因为它足够高效,(除其他外)它允许Windows少放一张软盘。不管精确的细节如何,Pascal调用约定确实使代码变小了一点,因为被调用的函数从堆栈中清理了参数,而不需要在调用函数的任何地方清理它们。对于从至少两个不同的地方调用的任何函数,这都是一个胜利(如果在其他地方打平)。

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

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

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