如何知道 Qt 项目是否正在使用调用约定?

How to know whether a calling convention is in use with a Qt project?

你知道,当你定义一个函数时,你可以同时定义它的调用约定,就像这样:

int __stdcall foo(int) { return 1; };
int __cdecl   bar(int) { return 1; };

而如果要使用此函数推导模板参数,则必须处理调用约定,例如:

template<typename T> void tmpl_func( T( __stdcall f )(T) ) { other_func<T>(); };

使用此模板,您只能使用“foo”作为参数。如果使用“bar”,则无法编译。

tmpl_func(foo);   // ok
tmpl_func(bar);   // err

因此,如果您有一个使用 __cdecl 的函数,您必须使用两种调用约定来定义模板函数,如下所示:

template<typename T> void tmpl_func( T( __stdcall f )(T) ) { other_func<T>(); };
template<typename T> void tmpl_func( T( __cdecl   f )(T) ) { other_func<T>(); };

foo实例化__stdcall版本,bar实例化__cdecl版本,没有重新定义。

总的来说,这很好用,但最近我遇到了一个问题:

在Qt项目中,当我按照上面所说的方式定义模板函数时,编译器说:__cdecl模板函数已经定义。

而如果在__stdcall版本中只定义tmpl_func,也可以使用bar 作为参数。

这是否意味着我编写的所有调用约定标识符都不起作用,并且所有函数都以__cdecl方式调用?

为什么以及我怎么知道这种情况是否会发生?我可以使用宏或编译选项检查它吗?

抱歉我的英语不好,我希望我已经说清楚了,但这确实困扰了我一段时间。

You know, when you define a function, you can define it's calling convention at the same time

这是错误的。您描述的是 C++ 的(特定于供应商的)扩展。例如,在 Linux 上我的 GCC 编译器上,它可能无法工作。

In a Qt project,

根本不要在您的 Qt 代码中使用任何 explicit__stdcall__cdecl 注释。

(在您的 Qt 代码中使用它是搬起石头砸自己的脚:它很疼;坚持 Qt5 项目的标准 C++11 代码)

如果你需要调用一些外部奇怪的函数(使用奇怪的&explicit调用约定)写一些extern "C" (或者一些 static inline 一个,如果它很短)包装函数这样做(并且你的包装函数有一个通常的签名,没有显式调用约定注释)。

实际上,在编写 Qt 项目时,您使用所有警告和调试信息对其进行编译(因此 g++ -Wall -g 如果使用 GCC),您使用 gdb 调试器对其进行调试,然后进行优化(例如用 g++ -Wall -g -O2 编译)它 - 例如对于基准测试和生产代码——你相信编译器可以很好地优化,内联许多函数调用,并选择足够好的调用约定。不要乱用 Qt 代码中的调用约定。

(隐含地你在问 __stdcall__cdecl 是否以及如何改变 C++ 的类型系统;并且 C++ 类型已经足够复杂,你不想要更乱)