我们有一个庞大的C ++代码库,有很多COM对象。暴露给COM的每个函数都必须具有__stdcall
调用约定(通常为STDMETHODCALLTYPE
宏),因此我们有许多标记为STDMETHODCALLTYPE
的函数。
现在我看到一个不是通过COM直接调用的函数,而是仅从我们的C ++代码中调用,并且此函数在其签名中也有STDMETHODCALLTYPE
个宏。我完全确定宏在那里没用 - 没有通过COM调用该函数。
我应该删除__stdcall
以使其成为“默认”调用约定函数吗?我该如何做出这样的决定?
答案 0 :(得分:9)
我的方法是对内部代码使用默认的编译器调用约定,并对跨模块边界导出的任何方法使用明确定义的显式调用约定。
大多数编译器的默认调用约定出于性能原因而充分利用了寄存器,因此在适当的地方使用寄存器是有好处的。它还使您的代码更容易,因为您不需要指定约定来获取默认值。
对于导出的函数,您显然需要指定约定。如果您正在创建一个预期将使用C或C ++以外的语言调用的库,那么使用stdcall是常规的。如果您只期望C或C ++客户端,那么cdecl可能是最常见的约定。
答案 1 :(得分:5)
当Windows从__ cdecl切换到_ _stdcall作为默认调用约定时,产品的大小下降了大约10%。这节省完全与在调用stdcall方法后删除堆栈调整有关(__cdecl是“调用堆栈以调整堆栈以删除参数”调用约定,__ stdcall是“callee调整堆栈以删除参数”调用约定,因为还有更多调用者比被调用者,切换减少了二进制文件的大小。)
使用__stdcall的缺点是你没有变量#s of argments(因为被调用者调整了堆栈,他们无法知道调用者指定了多少参数)。
底线:从“默认”调用约定切换到__stdcall可能会导致二进制文件的大小减小。这可能对你很重要,也可能不重要。
然而,正如上面提到的mkaes,如果你的代码是在另一个compiland中访问 EVER (例如,如果你将.lib文件传递给其他人),那么声明使用的调用约定绝对是至关重要的。
答案 2 :(得分:3)
COM东西显式设置调用约定的唯一原因是因为它跨DLL边界使用
所以我的建议是删除调用约定的显式设置并通过编译器设置进行设置
一般来说:
如果将函数导出为DLL,则设置一个宏,该宏在Headers中定义调用约定。这可以防止DLL在链接到DLL时使用错误的调用约定。显式覆盖编译器设置
不要对本地功能使用任何呼叫对流。约定可以由编译器开关设置。如果您决定明确设置一个,请在所有函数上执行。然后你仍然有一个改变呼叫惯例的中心位置
当然,如果它有意义,或者你需要一些特殊的调用约定,例如fastcall进行优化,那么你也需要明确设置。
答案 3 :(得分:2)
您是否启用了whole program optimization和link-time code generation?如果是这样,并且您没有从DLL导出函数或传递指向它的指针,那么编译器可能会为该函数生成自定义调用约定或内联它(即使它没有在头文件中定义)。
答案 4 :(得分:1)
通过搜索与解决方案关联的ODL文件,您可以查看地图以查看它是否被引用。如果不存在,则它没有接口,您可以更改调用约定。存在这样的风险:其他人假设所有功能都是使用此调用约定设置的,并且他们可以在以后添加接口。