c语言之函数调用约定

1 前言

在C和C++编程中,函数调用约定(Calling Convention)定义了函数参数如何传递、由谁负责清理栈(如果有的话)、以及返回值如何传递等规则。不同的平台和编译器可能采用不同的调用约定。以下是一些常见的调用约定及其特点的详细说明:

2 __cdecl

  • 定义与特点:
    __cdecl是C语言默认的调用约定,在C++中也可使用,但不是类成员函数的默认调用约定。
    参数从右向左压入堆栈。
    调用者负责清理堆栈,这意味着调用者需要知道传递了多少参数,并据此调整堆栈指针。
    支持可变参数列表的函数(如printf)必须使用此调用约定。
    函数名在编译后通常不会改变(尽管在某些编译器中可能会添加前缀,如下划线)。
  • 适用场景:
    C语言编写的程序。
    在Windows上用于一些API函数(尽管Windows API主要使用__stdcall)。
    需要实现可变参数列表的函数。

3 __stdcall

  • 定义与特点:
    __stdcall是Windows API中广泛使用的调用约定。
    参数也是从右向左压入堆栈,但与被调用者(callee)负责清理堆栈的__cdecl不同,__stdcall由被调用者清理堆栈。
    函数名在编译时会加上一个特定的后缀(如“_”前缀和参数总字节大小的“@”后缀),以区分调用约定。
    由于被调用者负责清理堆栈,这有助于减少调用者的工作量,并允许被调用者知道需要清理多少堆栈空间。
  • 适用场景:
    Windows API函数。
    需要跨语言或跨平台调用时,因为许多其他语言和平台都支持或能够模拟__stdcall调用约定。

4 __fastcall

  • 定义与特点:
    __fastcall是一种通过寄存器快速传递参数的调用约定。
    通常,函数的第一个和第二个参数(或更小的参数)通过特定的寄存器(如ECX和EDX)传递,其他参数则从右向左压入堆栈。
    被调用者负责清理堆栈。
    由于使用了寄存器传递参数,这种调用约定通常比仅使用堆栈的调用约定更快。
  • 适用场景:
    需要提高函数调用性能的场景。
    某些特定的编译器或平台可能默认使用此调用约定(如Borland C++ Builder)。

5 __thiscall

  • 定义与特点:
    __thiscall是C++中类成员函数的默认调用约定(但请注意,这并非所有编译器都遵循此约定,且__thiscall不是一个关键字,而是一个描述性的名称)。
    在这种调用约定中,“this”指针隐式地作为第一个参数通过寄存器(如ECX)传递给函数。
    其他参数从右向左压入堆栈。
    被调用者负责清理堆栈(尽管在某些情况下,如果参数个数不确定,调用者可能需要清理堆栈)。
  • 适用场景:
    C++类成员函数。

6 Naked Call

  • 定义与特点
    Naked Call是一种非常底层的调用约定,它不生成任何prolog(函数开头的保存寄存器代码)或epilog(函数结尾的恢复寄存器代码)代码。
    程序员需要手动编写这些代码,以控制函数的入口和出口。
    这种调用约定通常用于需要精确控制函数行为或与其他低级代码(如汇编语言)紧密集成的场景。
  • 适用场景
    编写需要与汇编语言代码紧密集成的函数。
    需要完全控制函数调用的堆栈和寄存器行为的场景。

7 总结

不同的调用约定适用于不同的场景和需求。了解这些调用约定的特点和适用场景有助于编写更高效、更可移植的代码。在选择调用约定时,需要考虑目标平台、编译器、以及与其他代码或库的兼容性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值