C和C++函数调用约定之间的转换[文].pdfVIP

  • 0
  • 0
  • 约5.68千字
  • 约 4页
  • 2021-10-13 发布于福建
  • 举报
C 语言的初学者常犯的一个失误是调用系统或第三方 API 时忘了在函数声明中标注 WINAPI 调用方式,而菜鸟 C++ 程序员也每每困惑为什么成员函数必须指示为 CALLBACK 再添加 static 关键字才能作为回调函数。在 x86 系统中,存在多种函数调用约定。如果调用者与被 调用者采用不同的调用约定,很可能导致堆栈破坏、非法访问等致命错误。 也许您会得出一个结论, 除非借助汇编指令, 否则调用约定之间的转换是不可能的。 不过很 多事情都不是绝对的。我们先看下面的例子: #include int __cdecl CDeclFunction() { printf(From CDecl function\n); return 1; } int main() { printf(Begin call STDCall function\n); typedef int(__stdcall * STDCALLFUNCTION)(); STDCALLFUNCTION pfn =(STDCALLFUNCTION)CDeclFunction; int i=pfn(); printf(End call STDCall function\n); return i; } 这是一个简单的函数调用的例子,唯一特别的地方是函数定义为 __cdecl ,而调用时采用 __stdcall 方式。我们把这段代码编译后执行。嗬,一切正常。如果您不服气,再加一个 for 循环看看 J 我们再来看另一个更特别的例子: #include int __stdcall StdCallFunction (int i, char* pszString) { printf(From STDCall function\n); printf(pszString); return i; } int main() { printf(Begin call FastCall function\n); typedef int(__fastcall * FASTCALLFUNCTION)(int, int, int, char*); FASTCALLFUNCTION pfn =(FASTCALLFUNCTION)StdCallFunction; int i=pfn(0,0,3,test\n); printf(End call FastCall function\n); return i; } 这次不光调用方式不同, 连参数的个数都不一样。 别担心, 我们编译后执行。 还是一切正常! 如果您对上述两个例子百思不得其解的话, 现在该是解开谜底的时候了。 这个谜底就是函数 调用约定本身。 网上介绍调用约定的资料已经相当多了, 不过几乎都侧重比较各种调用方式 的差别, 而本文将把重点放在这些调用方式之间的联系上面 (这里也略去诸多与主题无关的 细节,要想了解函数调用约定的所有方式,相应的汇编代码,以及在参数或返回值超过 32 位等复杂情况的处理方式,请查阅本文列出的参考书目) 。 调用函数时,需要传递参数,并接收返回值。对于 C++ 非静态成员函数,还要考虑如何传 递 this 指针。这要么采用寄存器,要么采用堆栈。如果采用堆栈,还要考虑由谁负责恢复堆 栈的平衡。调用约定即是调用者和被调用者之间传递参数和接收返回值的规范。对于

文档评论(0)

1亿VIP精品文档

相关文档