- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我发现了以下问题:Is fastcall really faster?
没有给出 x86 的明确答案,所以我决定创建基准。
代码如下:
#include <time.h>
int __fastcall func(int i)
{
return i + 5;
}
int _stdcall func2(int i)
{
return i + 5;
}
int _tmain(int argc, _TCHAR* argv[])
{
int iter = 100;
int x = 0;
clock_t t = clock();
for (int j = 0; j <= iter;j++)
for (int i = 0; i <= 1000000;i++)
x = func(x & 0xFF);
printf("%d\n", clock() - t);
t = clock();
for (int j = 0; j <= iter;j++)
for (int i = 0; i <= 1000000;i++)
x = func2(x & 0xFF);
printf("%d\n", clock() - t);
printf("%d", x);
return 0;
}
如果在 MSVC 10 中没有优化结果是:
4671
4414
使用最大优化 fastcall
有时会更快,但我猜这是多任务处理的噪音。这是平均结果(iter = 5000
)
6638
6487
stdcall
看起来更快!
以下是 GCC 的结果:http://ideone.com/hHcfP再次,fastcall
输了比赛。
这是 fastcall
的反汇编部分:
011917EF pop ecx
011917F0 mov dword ptr [ebp-8],ecx
return i + 5;
011917F3 mov eax,dword ptr [i]
011917F6 add eax,5
这是 stdcall
:
return i + 5;
0119184E mov eax,dword ptr [i]
01191851 add eax,5
i
是通过 ECX
传递的,而不是堆栈,而是保存在 body 的堆栈中!所以所有的效果都被忽略了!这个简单的函数可以只使用寄存器来计算!它们之间并没有真正的区别。
谁能解释 fastcall
的原因是什么?为什么它不提供加速?
编辑:经过优化,这两个函数都是内联的。当我关闭内联时,它们都被编译为:
00B71000 add eax,5
00B71003 ret
这看起来确实是一个很好的优化,但它根本不尊重调用约定,所以测试是不公平的。
最佳答案
__fastcall
是在 很久 之前引入的。当时,Watcom C++ 在优化方面击败了微软,许多评论者认为它基于寄存器的调用约定是一个(可能的)原因。
Microsoft 通过添加 __fastcall
作为回应,从那以后他们一直保留它——但我认为他们所做的还远远不够能够说“我们有一个寄存器——也基于调用约定...”他们的偏好(尤其是自从 32 位迁移以来)似乎是 __stdcall
。他们在使用它改进代码生成方面投入了大量工作,但(显然)使用 __fastcall
并没有那么多。使用片上缓存,在寄存器中传递内容的 yield 并不像当时那么大。
关于c++ - 为什么fastcall比stdcall慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5479362/
据我所知,只有 caller-clean-stack 约定可以使用变量参数。 顺便说一句,WinApi StringCchPrintfW 是这样声明的。(我删除了 SAL) __inline HRES
现在我正在设计一个函数f(index,...),它将调用函数数组中的#index条目并传递其余参数。如果您将函数数组视为服务列表,那么 f 的作用就像一个服务分发器。 f 是用汇编语言编写的。它弹出第
我对此很好奇: 当我从使用stdcall调用约定导出的动态链接库导入函数时,是否必须在external之前添加stdcall Delphi 从版本 7 开始? 即 LIBNAME int __stdc
在我的库中,我在特定条件下调用方法,这需要 stdcall 调用约定。目前,我正在使用编译器静态解析,将其实现为相当大的众所周知的方法签名列表和子例程的相应重载版本。这可行,但看起来很丑陋,并且没有
使用 D 内联汇编尝试实现动态调用 stdcall 函数(使用动态参数) 我有以下程序集args 是一个指向 32 位整数数组的 void 指针 argc 是参数计数的数量 ret 是一个 void
我正在将代码从 C++ 转换为我的 VB.NET 应用程序。这是 C++ 代码: typedef int (__stdcall *init_t)(uint32_t value,uint32_t pa
我正在编写一些使用 jni 的代码。我的目标平台是 Windows。所以我的 jni 函数必须使用 stdcall 调用约定,但 Rust 仅使用 cdecl 调用约定导出函数。 我使用 MinGW(
我无法将 stdcall 函数名称“TestFunction”作为参数传递给 ExecuteLocalThread 并在 beginthreadex 中使用 unsigned __stdcall Te
我正在使用 GCC 处理我自己的内核,当从 asm 代码调用 C 函数时,我必须做 add esp,xx我自己。经过一番搜索,我发现 stdcall是微软的发明,不能在 GCC 中使用。有什么方便的方
我目前正在尝试移植旧的 owl-c++-builder-projekt 以使用 XE2 和 owlnext。在旧文件中,我可以简单地调用一行 (FARPROC)LP_I2COpen = GetProc
我正在尝试使用具有回调机制的 (C) 第三方库,该机制缺少任何可能的识别调用上下文的方法。我的主要项目在 C# 中,我的包装器是一个调用 C 库 API 的 C++/CLI 项目。 为了解决这个问题,
有人可以给我一些为 MS winapi 函数创建函数指针的技巧吗?我正在尝试为 DefWindowProc (DefWindowProcA/DefWindowProcW) 创建指针,但出现此错误: L
我有简单的代码。 StdCall 是 __stdcall 而 CdeclCall 是 __cdecl。 #include int __stdcall StdCall(int a,int b) {
我有一个指向 COM 接口(interface)的指针,想从它的虚拟表中获取函数指针并进行方法调用。为此,我需要进行 stdcall 方法调用。在 Go 中如何使用约定 stdcall 进行调用或在
我制作了一个 DLL,它导出多个函数(使用 stdcall)。我想让其中一些接受或不接受参数。所以懒惰的程序员可以直接调用它而不需要任何参数。我在论坛上的某个地方读到默认参数在 DLL-s 中不起作用
我正在设计一个必须至少在 mingw 和 msvc++ 之间二进制兼容的 API。到目前为止,我限制自己使用接受和返回原始数据类型的函数或指向具有统一成员的 POD 结构的指针(即,成员都是同一类型,
在 Windows 下构建 DLL 时,我得到以下输出: Linking main.exe ... Warning: resolving _findPeaksWrapper by linking to
这个问题已经有答案了: Is there any equivalent for stdcall in GCC? (1 个回答) Is there STDCALL in Linux? (3 个回答) 已
我试图通过创建指定我需要使用的函数的 .def 文件,将函数从非托管 DLL 导入到 C 项目中。我正在练习 user32.dll 中的 WinAPI 函数 MessageBoxA。与其他 WinAP
我需要创建一个 C++ dll,它将通过 stdcall 从另一个程序调用。 需要什么:调用程序将字符串数组传递给 dll,dll 应该更改数组中的字符串值。然后,调用程序将继续使用来自 dll 的这
我是一名优秀的程序员,十分优秀!