有关通话约定的问题

我记得很久以前,当我使用Turbo C时,我不需要关心函数的调用约定,我使用或定义的每个函数都采用C调用约定的forms。

但是在我转到Windows平台之后,我发现有这么多的调用会话指示符,比如:

WINAPI,STDCALL,__cdecl …

这是编译器演变的结果吗?

不,它的简单或主要是Windows API的历史遗产。 Windows之外的大多数系统并不经常使用不同的调用约定(例外:系统调用和内核模式)。

不同的调用约定具有不同的特征,有时使用的语言或API可能需要不同的特征。 查阅这篇文章,了解不同调用约定的概述,以及哪些API通常使用它们。

WINAPI,STDCALL等…不是调用约定,它们是定义调用约定的宏。 实际上只有两三种实际类型。 宏的原因是为了向后兼容。

不,这是微软白痴的结果。 没有理由不同的调用约定应该在C环境中使用/混合过。

调用约定是非常重要的,但你很少需要考虑。

当以其他语言编写的其他操作系统或对象\库(如pascal等)时,它变得相关。

它决定了什么以及如何在堆栈上(通过调用者)推送参数,以及负责在被调用函数返回时从堆栈中弹出这些参数的人员。

由于C \ C ++支持可变参数列表,因此调用者的任务是弹出堆栈(因为被调用者不知道给出多少个参数)。

因此,这会导致大量生成的代码(每个函数调用都会使用堆栈弹出代码进行扩展)。

然而,不允许本地变量参数列表的语言可以通过被调用的函数(它们总是知道它是如何调用的)来释放堆栈的负担。 这将导致只有一个堆栈弹出代码(在被调用者的末尾),因此生成的代码较少。

进一步更多的语言可以选择HOW参数堆叠的方式。 它可以选择按照它们在调用中写入的顺序(第一个参数第一个参数,最后一个参数最后一个参数)推送参数,或者可以选择最后一个参数,最后一个参数(如C \ C ++)。 后者允许可变参数列表的“简单”实现。

如果你不使用变量参数列表,你可以选择不同的默认调用约定(如PASCAL)。 然而,这意味着没有指定调用约定的每个函数都将按照您选择的约定进行处理。 如果声明与实现不同,则可能会得到无法解析的外部错误(最多)或严重的运行时错误或(最坏的情况下)错误的计算。

作为一个实际的例子:我曾经是一个移动电脑制造商的程序员。 他们使用一个特殊的(有限的)编译器来生成紧凑的代码(移动计算机的内存非常有限),因为MSVC生成了大对象。

我建议把C调用约定改成pascal调用约定和其他一些小的改变。 从那以后,他们可以使用更复杂的编译器(MSVC)并做更多的事情。