【问题标题】:Does every function in a Windows GUI application need to use stdcall?Windows GUI 应用程序中的每个函数都需要使用 stdcall 吗?
【发布时间】:2021-02-25 11:43:45
【问题描述】:

据我了解,调用者和被调用者都需要具有相同的调用约定。否则,堆栈可能已损坏。

WinMain__stdcall 声明并调用我定义的所有函数。这是否意味着我定义的所有函数都应该使用stdcall 调用约定?

我试过不使用__stdcall 并没有发生任何不好的事情。我还看到支持 Windows 的知名 GUI 库不使用 stdcall。为什么堆栈没有损坏?

【问题讨论】:

  • 调用者和被调用者必须就被调用者的调用约定达成一致。调用者和被调用者本身有不同的约定是很常见的。您可能已经在自己做:C 标准库中的所有函数都是 cdecl,但您可以从 WinMain 调用它们。
  • 调用约定是调用者和被调用者之间的契约。如果您调用库(如 Windows API),则必须遵循库的合同。如果你实现了一个库,你可以决定使用哪个调用约定。如果您以 x64 为目标,事情就不那么复杂了:只有一种调用约定。

标签: c winapi calling-convention


【解决方案1】:

WinMain 用__stdcall 声明并调用我定义的所有函数。这是否意味着我定义的所有函数都应该使用stdcall 调用约定?

没有。调用约定是在每个函数调用的基础上处理的,就在调用站点。约定规定了调用者和被调用者如何管理调用堆栈——参数如何传递、以什么顺序、谁清理堆栈等。只要调用者和被调用者同意在每个单独的函数调用上使用相同的调用约定, stdcall 函数调用使用不同约定的函数(如 cdecl)是完全安全的,反之亦然。函数的调用约定仅适用于:

  • 新调用者正在输入该函数。
  • 函数正在返回给调用者。
  • 函数正在访问自己的参数。

除此之外,函数在内部执行的操作与其自身的调用约定无关。

例如,假设WinMain(),一个stdcall 函数,想要调用一个cdecl 函数。

WinMain() 本身就是一个stdcall 函数并不重要。虽然代码执行在WinMain() 内部,但它可以为所欲为。 WinMain()stdcall 约定仅适用于WinMain() 本身的进入和退出。这就是WinMain() 与 ITS 调用者的合同。

重要的是WinMain() 在为即将调用的cdecl 函数设置调用堆栈时必须遵循cdecl 的规则,并在该函数返回时清理调用堆栈WinMain().

任何调用约定的任何函数调用都是如此。

我试过不使用__stdcall 并没有发生任何不好的事情。我还看到支持 Windows 的知名 GUI 库不使用 stdcall。为什么堆栈没有损坏?

因为调用堆栈在每次函数调用和返回时都得到了正确的管理,所以没有不平衡的清理来破坏堆栈。

【讨论】:

  • 是什么让调用约定彼此一致?我最初以为他们只有在具有相同的调用约定时才同意,但显然不是。
  • 我最初认为他们只有在具有相同的调用约定时才会同意”——这完全正确。如果给定函数的调用者声明使用被调用者在函数实现中使用的相同调用约定,那么事情就很好了。如果调用者使用不同的约定,那么您就会遇到问题。 “但显然不是”——你为什么会这样认为?
  • stdcall 和 cdecl 都是不同的调用约定,但它们仍然彼此一致。我知道当他们有相同的调用约定时他们仍然同意,但我不明白为什么 cdecl 和 stdcall 彼此同意,即使它们都是不同的。
  • "stdcall 和 cdecl ... 仍然彼此一致" - 不,他们不同意,因为它们有不同的清理规则。在stdcall 中,被调用者 清理调用堆栈。在cdecl 中,调用者 进行清理。您过于关注调用者对其 OWN 堆栈帧使用的约定,而不是调用者用于 CALL THE NEXT FUNCTION 的约定。我已经更新了我的答案以反映这一点。
  • @kurupreo:你似乎认为“WinMainstdcallprintfcdecl,因此如果 WinMain 调用 printf,那么调用者 = stdcall 和callee = cdecl" 并试图将这些替换为 Remy 的声明“调用者和被调用者同意”以获得“stdcallcdecl 同意”。 这不是调用约定的工作方式。 WinMainstdcall 会影响 return 内部的 WinMain 语句。它不会影响函数体的任何其余部分。它也会影响调用WinMain 的(工具链提供的)函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多