我应该选择“默认”吗?当我并不真正关心调用约定时,通过 __fastcall 调用约定?
我们有一个巨大的 C++ 代码库,其中包含大量 COM 对象。每个暴露给 COM 的函数都必须有 __stdcall
调用约定(通常是 STDMETHODCALLTYPE
宏),因此我们有很多标记为 STDMETHODCALLTYPE
的函数。
现在我看到一个函数不是通过 COM 直接调用,而是仅从我们的 C++ 代码中调用,并且该函数的签名中还包含 STDMETHODCALLTYPE
宏。我完全确定该宏在那里毫无用处 - 不会通过 COM 调用该函数。
我应该删除 __stdcall 以便它成为“默认”调用约定函数吗?我该如何做出这样的决定?
We have a huge C++ codebase with lots of COM objects. Each function exposed to COM must have __stdcall
calling convention (usually STDMETHODCALLTYPE
macro) and so we have lots of functions marked STDMETHODCALLTYPE
.
Now I see a function that is not directly called through COM, but rather called only from within our C++ code and this function also has STDMETHODCALLTYPE
macro in its signature. I'm completely sure that macro is useless there - no calls through COM to that function ever happen.
Should I drop the __stdcall
so that it becomes a "default" calling convention function? How do I make such decisions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我的方法是对内部代码使用默认的编译器调用约定,并对跨模块边界导出的任何方法使用明确定义的显式调用约定。
出于性能原因,大多数编译器的默认调用约定都充分利用了寄存器,因此在适当的情况下使用它是有好处的。它还使您的代码更易于查看,因为您不需要指定约定来获取默认值。
对于导出的函数,您显然需要指定约定。如果您正在创建一个预计将从 C 或 C++ 以外的语言调用的库,那么通常会使用 stdcall。如果您只期望 C 或 C++ 客户端,那么 cdecl 可能是最常见的约定。
My approach is to use the default compiler calling convention for internal code and to use a well-defined explicitly stated calling convention for any methods which are exported across a module boundary.
The default calling convention for most compilers makes good use of registers for performance reasons so there are advantages to using it where appropriate. It also makes your code easier on the eye since you don't need to specify the convention to get the default.
For exported functions you clearly need to specify the convention. If you are making a library that you anticipate will be called from languages other than C or C++ it would be conventional to use stdcall. If you only expect C or C++ clients then cdecl is probably the most common convention.
当 Windows 从 __cdecl 切换为 __stdcall 作为默认调用约定时,产品的大小下降了大约 10%。这种节省完全与调用 stdcall 方法后删除堆栈调整有关(__cdecl 是“调用者调整堆栈以删除参数”调用约定,__stdcall 是“被调用者调整堆栈以删除参数”调用约定,因为有更多调用者而不是被调用者,切换会减少二进制文件的大小)。
使用 __stdcall 的缺点是没有可变的参数(因为被调用者调整堆栈,他们不知道调用者指定了多少个参数)。
底线:从“默认”调用约定切换到 __stdcall 可以减少二进制文件的大小。这对你来说可能重要也可能不重要。
然而,正如上面提到的,如果您的代码曾经在另一个编译器中被访问(例如,如果您将 .lib 文件交付给其他人),那么声明所使用的调用约定是绝对重要的。
When Windows switched from __cdecl to __stdcall as the default calling convention, the size of the product dropped by about 10%. That savings was entirely related to removing the stack adjustments after calling the stdcall methods (__cdecl is a "caller adjusts the stack to remove parameters" calling convention, __stdcall is a "callee adjusts the stack to remove parameters" calling convention, since there are more callers than callees, switching reduces the size of your binaries).
The downside of using __stdcall is that you don't have variable #s of argments (since the callee adjusts the stack, they can't know how many parameters the caller specified).
Bottom line: switching to __stdcall from the "default" calling convention can result in a reduction in size of your binary. That may or may not be important to you.
However as mkaes mentioned above, if your code is EVER accessed in another compiland (for instance if you deliver a .lib file to someone else), it's absolutely critical that you declare the calling convention used.
COM 内容显式设置调用约定的唯一原因是因为它是跨 DLL 边界使用的。
所以我的建议是放弃调用约定的显式设置并通过编译器设置进行设置。
一般来说:
如果函数导出为 DLL,则设置一个在标头中定义调用约定的宏。这可以防止 DLL 的用户在链接到 DLL 时使用错误的调用约定。显式覆盖编译器设置。
不要在局部函数上使用任何调用对流。约定可以通过编译器开关设置。如果您决定明确设置一项,请对所有函数执行此操作。那么您仍然可以在一个中心位置更改调用约定。
当然,如果它有意义或者您需要一些特殊的调用约定(例如用于优化的 fastcall),那么您也需要显式设置。
The only reason why the COM stuff explicitly sets the calling convention is because it is used across DLL boundaries.
So my advise would be to drop the explicit setting of the calling convention and set it by the compiler settings.
In general:
If the functions are exported as a DLL set a macro that defines the calling convention in the Headers. This prevents users from the DLL to use a wrong calling convention when linking to your DLL. Explicit overrides the compiler setting.
Do not use any calling convection on local functions. Convention can be set by a compiler switch. If you decide to set one explicitly, do it on all Functions. Then you still have a central place to change the calling convention.
Of course if it makes sense or you need some special calling convention e.g fastcall for optimization then you need to set explicitly too.
您是否有整个程序优化和链接时代码生成已启用?如果是这样,并且您不从 DLL 导出该函数或传递指向它的指针,那么编译器可能会为该函数生成自定义调用约定或内联它(即使它没有在头文件中定义)。
Do you have whole program optimization and link-time code generation enabled? If so, and you don't export the function from your DLL or pass around pointers to it, then the compiler may generate custom calling conventions for that function or inline it (even if it's not defined in a header file).
您可以通过搜索与解决方案关联的 ODL 文件来浏览地图以查看它是否被引用。如果不存在,则它没有接口,您可以更改调用约定。存在这样的风险:其他人假设所有函数都是使用此调用约定设置的,并且他们可以在以后添加接口。
You could look through your maps to see if it is referenced, by searching the ODL files associated with the solution. If its not there, it doesn't have an interface, and you can change the calling convention. There is the risk that someone else assumes all functions are set up with this calling convention, and they could add an interface at a later date.