为什么我不应该使用__fastcall而应该使用标准的__cdecl?

13

我听到一些人说__fastcall__cdecl__stdcall更快,因为它将两个参数放在寄存器中,而其他调用只有一个;但是,在另一方面,这不是C语言中使用的标准。

我想知道什么使__fastcall成为C语言标准中不理想的选项,以及何时在我的代码中使用它。


2
这非常依赖于平台。最好列出架构、操作系统和工具版本。 - Ben Voigt
2
stdcall和cdecl不会将参数放入寄存器中,而fastcall在可能的情况下会将4个参数放入寄存器中。 - Daniel
3
@Lucas 请参考https://dev59.com/uXI95IYBdhLWcg3wtwRe#2189914。 - sashoalm
4
this is not the standard used in C” 的意思是“这不是C语言使用的标准”。这些关键词和调用约定并不属于C语言标准的一部分,C语言标准没有提到过它们。 - Robᵩ
2个回答

14

x86平台不像其他平台一样定义了全局ABI和调用规则。

Win32/x86平台有一个标准的调用规则,即使用stdcall。不同的调用规则之间存在各种权衡——将参数放在寄存器中更快,但它会迫使调用者溢出先前正在使用这些寄存器的任何内容。因此很难预测哪个规则具有更好的性能。

重要的是要有一个统一的标准调用规则,以实现不同编译器(甚至不同编程语言)之间的互操作性。

其他平台没有cdeclstdcallfastcall调用规则,它们也没有相同的寄存器集合,有些情况下甚至没有寄存器。但它们仍然可以使用C代码。

Win32/x86_64不使用stdcall,而是使用64位扩展的fastcall

Linux/x86也有自己的调用规则。


这正是我想知道的。感谢您的回答。 - lucastamoios
我不会说这很不寻常。没有任何指令集架构有固有的调用约定;调用约定是在 ISA 之上构建的契约,并且对于类 Unix 系统,通常遵循特定架构的 psABI,该 ABI 基于源自 Unix System V 的 gABI 演变而来。一些像 ARM 这样的 ISA 具有一个或多个由 ISA 创建者开发、推广和/或赞助的 ABI,但仍然没有根本性的原因必须使用它们。我认为在这方面,x86 是常态,而不是例外。 - R.. GitHub STOP HELPING ICE
@R..:无论如何,今天没有标准化的ABI是不寻常的。原因是x86是过去时代的遗物,当时人们并未意识到它的好处。 - Ben Voigt
什么是 Linux 的惯例? - Nande
1
Windows x64调用约定并非“架构定义”。它是由微软公司内部开发的。x86-64 System V ABI是由GCC开发人员设计的,也没有得到英特尔或AMD的官方认可。然而,在AMD64架构师和Linux内核开发人员也在同一公共邮件列表上讨论了这个问题。请参阅我的答案为什么Windows64使用与x86-64上的所有其他操作系统不同的调用约定?以获取一些存档链接。 - Peter Cordes
显示剩余7条评论

4
你是否正在寻找一种用于指定库接口的调用约定?因为对于所有其他函数,我不会指定任何调用约定。编译器的优化过程(例如自动内联)可能使调用约定无用。
但是关于fastcall:据我所记,它没有标准化,因此不适合库代码。这里有一个很好的概述:调用约定解密

1
我认为所有可以针对Windows的主要x86编译器都可以将函数原型标记为fastcall。MSVC可以,其他编译器支持GNU C __attribute__((fastcall))。顺便说一句,你链接的文章展示了调试模式下的汇编代码。难怪他们没有发现它更快;被调用者正在将寄存器参数溢出到堆栈中,然后重新加载它们,完全违背了与lea / ret相比的目的。(它还声称MS保留更改fastcall以使用不同寄存器的权利。如果这是真的,那么它将不适用于库,但我不知道是否是真的。) - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接