【问题标题】:What is the point of defining a calling convention?定义调用约定有什么意义?
【发布时间】:2012-03-01 16:54:07
【问题描述】:

例如:

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

WINAPI 是一个如下所示的定义:

#define WINAPI      __stdcall

你为什么不能这样做:

int __stdcall WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

实际上我认为我的问题是我有点混淆了 typedef 的定义。谁可以给我解释一下这个?定义是做什么的,为什么你不能只写 __stdcall 代替它?

【问题讨论】:

    标签: c++


    【解决方案1】:

    因为WINAPI 调用约定不保证__stdcall。使用WINAPI 的代码即使不是正确的也仍然正确。

    可以像在后面的示例中那样编写函数,并且它可以正常工作 - 这不是一个好的做法,并且不能移植到调用约定是其他东西的平台上。

    【讨论】:

    • 好吧,其实你错了。因为现在不可能改变这个约定。想象一下,如果微软突然把 WINAPI 改成 __cdecl,那么每一个用以前版本的 Win Api 头编译的程序都会不能正常运行
    • 这对于不同的平台是有意义的。只有 x86 有 __stdcall,所以希望 WINAPI 在 ARM 上是一个空宏。
    • @kids_fox 显然二进制文件不会仍然有效,但代码会。
    • @James,关于 x86 的约定没有改变,他是对的——尽管假设整个世界都是 x86 是错误的。
    • @SimonRichter,谢谢,我知道这一点 :) 鉴于您的澄清,我的回答现在无关紧要
    【解决方案2】:

    这最初是在从 16 位代码切换到 32 位代码期间完成的。在 <windows.h> 的 16 位版本中是:

    #define WINAPI __pascal
    

    WINAPI 允许您在不修改源代码的情况下进行编译。当然,16 位 Windows 不再是一个因素(至少对大多数人来说),但仍然不值得将所有源代码更改为直接使用 __stdcall(尤其是因为它可能有一天会再次更改)。

    【讨论】:

      【解决方案3】:

      可以只写 __stdcall 代替它,但不要。他们认为#define WINAPI 到 __stdcall 以使其不透明是合适的,这只是一种很好的编程习惯。

      【讨论】:

        【解决方案4】:

        此外,在过去,一些 Windows 库使用 Pascal 调用约定,而其他库使用 C 约定。预处理器定义有助于掩盖这一点。

        【讨论】:

          【解决方案5】:

          因为 WINAPI 是一个宏(无论如何都是#define),它可以被“预处理”以表示其他含义,甚至根本没有含义。

          这意味着您可以编写更多可移植代码,因为当 Win32 要求它表示 __stdcall 但是,或者如果在另一个环境中要求它表示其他或什么都没有时,您可以放入 WINAPI。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-14
            • 1970-01-01
            • 2023-03-17
            • 2012-10-06
            • 1970-01-01
            • 2011-12-03
            • 2012-11-28
            相关资源
            最近更新 更多