为什么不是所有的 C 程序都使用调用约定

Why calling conventions aren't used in all C programs

我是编程新手,在阅读 Charles Petzold 的书 编程 Windows 时,我偶然发现了 WINAPI(实际上我对函数的前面还有另一个词感到惊讶除了 return 类型之外的名称)并发现它是一个 调用约定 并且据我所知,它是函数如何将变量压入堆栈并获取的一种方式return 值,我想知道为什么我们不在每个 C 程序中使用它们?它们只是 OS 编程所独有的吗?

调用约定通常与编译器、体系结构和(在使用系统运行时库时)OS;它们根本不是 C 标准的一部分。在大多数情况下,给定的 architecture/compiler/OS 组合只有一个调用约定,因此您无需考虑;它只是使用 OS 支持的唯一约定。

在最近的历史中,它最重要的一个地方是在 32 位 x86 系统上,尤其是在 Windows 上。 x86 有很少的通用寄存器,所以只有少数可用,比典型函数可能需要的参数少,并且将它们用于参数传递意味着您经常需要将它们过去包含的任何内容推入堆栈,所以调用约定涉及很多权衡(在寄存器中传递参数更快,但前提是调用者可以节省寄存器或者至少不会被迫过度溢出到堆栈),并且 Windows继续“我们将在不同的场景中使用它们”。

在 x86-64(寄存器匮乏的情况要少得多)和非 x86 架构(通常有足够的寄存器)上的现代用法中,大多数 compilers/OSes 坚持单一的通用调用约定,所以再次,你不需要关注。这是一个好奇心,除非你在汇编中手写整个功能,否则你不需要亲自注意。

我们确实在所有 C 程序中使用调用约定,但它们在编译器设置中通常是默认值,因此不必显式 在代码中,除非实际需要(库交互等)。

调用约定不是 C 语言本身的一部分,而是作为语言的扩展由编译器供应商处理。

大多数 C 编译器通常默认使用 __cdecl 调用约定,但编译器用户可以根据需要更改此约定。曾几何时,Windows API 使用 来使用 __pascal,但现在很长 时间 __stdcall 正在被使用。因此存在 WINAPI 预处理器宏,因此 Microsoft 可以在它们之间切换而无需重写大多数现有代码。