我已经看到在许多函数之前附加了fastcall表示法。为什么使用它?

最佳答案

函数之前的表示法称为“调用约定”。它指定编译器如何(在较低级别上)将输入参数传递给函数并在执行后检索其结果。

有许多不同的调用约定,最流行的是stdcallcdecl

您可能会认为只有一种方法可以执行此操作,但实际上,您可以使用多种方法来调用函数并传入和传出变量。您可以将输入参数放在堆栈上(按,推,按通话;弹出,弹出,弹出以读取输入参数)。或者,您可能宁愿将它们粘贴在寄存器中(这是fastcall-为了速度,它试图将某些输入参数放入寄存器中)。

但是那顺序呢?您是从左到右还是从右到左插入它们?结果如何-总是只有一个(假设没有引用参数),那么您是否将结果放在某个内存地址的寄存器中的堆栈中?

另外,假设您使用堆栈进行通信-调用方还是被调用方,在调用函数后实际上要清除堆栈的工作是谁?

备份然后还原(某些)CPU寄存器的内容又如何-调用方应该这样做,还是被调用方保证它会以原样返回所有内容?

到目前为止,最受欢迎的调用约定是cdecl,它是C和C++中的标准调用约定。 WIN32 API使用stdcall,这意味着任何调用WIN32 API的代码都需要使用stdcall进行这些函数调用(这是另一个流行的选择)。
fastcall有点奇怪-人们意识到只有一个输入/输出参数才能实现许多功能,从基于内存的堆栈中压入和弹出操作会产生大量开销,并使函数调用有点繁重,因此引入了不同的编译器(不同的)调用约定,该约定将一个或多个参数放置在寄存器中,然后将其余参数放置在堆栈中,以提高性能。问题是,并不是所有的编译器都对fastcall使用什么规则以及去哪里做什么,谁来做呢?因此,在使用它时必须要小心,因为您永远不会知道谁在做什么。最后,请参阅Is fastcall really faster?以获取有关fastcall性能优势的信息。

复杂的东西。

需要记住的重要事项:如果您不完全知道自己在做什么,请不要添加或更改调用约定,因为如果主叫方和被叫方都不同意调用约定,那么您很可能最终会失败与堆栈损坏和段错误。当您在DLL/共享库中调用函数并且编写的程序依赖于DLL/SO/dylib是某个调用约定(例如cdecl),然后使用不同的调用重新编译该库时,通常会发生这种情况约定(例如fastcall)。现在,旧程序无法再与新库通信。

关于visual-c++ - visual c中使用的fastcall关键字是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10671281/

10-11 23:08
查看更多