stdcall和cdecl [英] stdcall and cdecl

查看:430
本文介绍了stdcall和cdecl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有两种类型的调用约定:stdcall和cdecl。我有几个问题。


  1. 当调用者调用cdecl函数时,调用者
    如何知道是否应释放堆栈?在调用站点,
    调用者是否知道被调用的函数是cdecl还是stdcall
    函数?它是如何工作的 ?调用者如何知道是否应该
    释放堆栈?

  2. 如果一个被声明为stdcall的函数调用一个函数(
    有一个调用约定为cdecl),或者反过来,
    这不恰当吗?

  3. 一般来说,我们可以说哪个调用会更快 - cdecl或
    stdcall?


    1. 解决方案

      Raymond Chen对 __ stdcall __ cdecl 做了一个很好的概述。 p>

      (1)调用者在调用函数之后知道清理堆栈,因为编译器知道该函数的调用约定并生成必要的代码。

        void __stdcall StdcallFunc(){} 

      void __cdecl CdeclFunc()
      {
      / /编译器知道StdcallFunc()在此时使用__stdcall
      //约定,因此它为堆栈清理生成适当的二进制
      //。
      StdcallFunc();
      }

      可能不匹配的调用约定,像这样:

        LRESULT MyWndProc(HWND hwnd,UINT msg,
      WPARAM wParam,LPARAM lParam);
      // ...
      //编译器通常抱怨,但是有这里转换...
      windowClass.lpfnWndProc = reinterpret_cast< WNDPROC>(& MyWndProc);

      很多代码示例得到这个错误,甚至不是很有趣。它应该是这样的:

        // CALLBACK是#define'd作为__stdcall 
      LRESULT CALLBACK MyWndProc hwnd,UINT msg
      WPARAM wParam,LPARAM lParam);
      // ...
      windowClass.lpfnWndProc =& MyWndProc;然而,假设程序员不忽略编译器错误,编译器将生成需要清除的代码(例如:



      <因为它会知道涉及的函数的调用约定。



      (2)两种方法都应该工作。实际上,这至少在与Windows API交互的代码中频繁发生,因为 __ cdecl 是根据Visual C ++编译器的C和C ++程序的默认值 WinAPI函数使用 __ stdcall 约定



      (3)两者之间应该没有真正的性能差异。


      There are two types of calling conventions - stdcall and cdecl. I have few questions on them.

      1. When a cdecl function is called by the caller, how does a caller know if it should free up the stack ? At the call site, does the caller know if the function being called is a cdecl or a stdcall function ? How does it work ? How does the caller know if it should free up the stack or not ? Or is it the linkers responsibility ?
      2. If a function which is declared as stdcall calls a function(which has a calling convention as cdecl), or the other way round, would this be inappropriate ?
      3. In general, can we say that which call will be faster - cdecl or stdcall ?

      解决方案

      Raymond Chen gives a nice overview of what __stdcall and __cdecl does.

      (1) The caller "knows" to clean up the stack after calling a function because the compiler knows the calling convention of that function and generates the necessary code.

      void __stdcall StdcallFunc() {}
      
      void __cdecl CdeclFunc()
      {
          // The compiler knows that StdcallFunc() uses the __stdcall
          // convention at this point, so it generates the proper binary
          // for stack cleanup.
          StdcallFunc();
      }
      

      It is possible to mismatch the calling convention, like this:

      LRESULT MyWndProc(HWND hwnd, UINT msg,
          WPARAM wParam, LPARAM lParam);
      // ...
      // Compiler usually complains but there's this cast here...
      windowClass.lpfnWndProc = reinterpret_cast<WNDPROC>(&MyWndProc);
      

      So many code samples get this wrong it's not even funny. It's supposed to be like this:

      // CALLBACK is #define'd as __stdcall
      LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg
          WPARAM wParam, LPARAM lParam);
      // ...
      windowClass.lpfnWndProc = &MyWndProc;
      

      However, assuming the programmer doesn't ignore compiler errors, the compiler will generate the code needed to clean up the stack properly since it'll know the calling conventions of the functions involved.

      (2) Both ways should work. In fact, this happens quite frequently at least in code that interacts with the Windows API, because __cdecl is the default for C and C++ programs according to the Visual C++ compiler and the WinAPI functions use the __stdcall convention.

      (3) There should be no real performance difference between the two.

      这篇关于stdcall和cdecl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆