函数调用约定 (cdecl stdcall)

在 C 语言里,我们通过阅读函数声明,就知道怎么携带参数去调用函数,也能在函数体定义内使用这些参数。但是 CPU 并不直接完成函数调用的传参操作,这需要人为的约定。这些约定被编译器识别和使用,生成所需的代码。

一般每个线程都维护着一个堆栈,称为调用栈。调用方想进行函数调用并传递参数,就往栈里压入参数。被调函数从栈顶取出一定数量的参数使用,这就完成了参数的传递。这个过程需要一些约定,使调用方和被调函数都能正确地识别对应参数的位置等。

顺便一提,函数返回值是怎么实现的呢?是往调用栈里压入了一个空值占位,被调函数往这个位置写入返回值,调用方再取出来使用,这就完成了返回值的传递。

函数调用约定主要包括三方面的内容:

压栈时的参数顺序,是从左至右还是从右至左

调用完成后堆栈由谁清理,是调用方还是被调函数

编译器的函数名修饰约定

主要有 cdecl stdcall 两种不同的约定,同时这也是 C 的关键字。

cdecl

cdecl 表示:

参数从右至左入栈

调用方来维护堆栈

告知 C 编译器,输出的函数名应该前加 _,即修饰为 _

cdecl 是 C/C++ 的默认函数调用约定。

在使用时,用特定的关键字来修饰函数名,Windows 下常用的 Visual C++ Compiler 支持 __cdecl;Linux 下常用的 GCC 支持 __attribute__((cdecl))。

cdecl 带来了两件事:

被调函数虽然不知道有多少参数入了栈,但会自上而下按需取走需要的参数。你可能想到了,使用可变参数(vararg/stdarg)的函数(如 printf)就只能使用 cdecl 约定。

每次函数调用后都要生成一段清栈代码,生成的目标代码会比较大

stdcall

stdcall 又称为 Pascal 约定,因为这也是 Pascal 语言使用的函数调用约定。

stdcall 表示:

参数从右至左入栈

被调函数来维护堆栈。这一过程一般通过指令 retn x 完成,x 是参数占用的字节数(记为 )

告知 C 编译器,输出的函数名应该前加 _ 后跟 @,即修饰为 _@

这里的第三点,举例说明:在 win64 环境下,函数 int __stdcall foo(void * p) 就可以在外部使用 _foo@8 来引用。

在使用时,vc++ 下使用 __stdcall;gcc 下使用 __attribute__((stdcall))。

在 Windows 编程中,宏 CALLBACK WINAPI 都指向 __stdcall。

因为 stdcall 严格控制了参数的字节数,所以不能实现可变参数。

__fastcall __thiscall

在 __stdcall 之上,引入了两个优化版本 __fastcall __thiscall。

__fastcall 将前两个或多个参数由寄存器传递(由编译器选决定选用哪些寄存器),以优化大多数参数个数较少的函数的调用耗时。C 编译器输出的函数名修饰为 @@。

__thiscall 是 C++ 中引入的,这不是关键字,不可手动指定,而是针对类成员函数自动添加,将 this 指针放在特定寄存器中(由编译器自行决定)。

__fastcall 和 __thiscall 都与编译器相关,可移植性较差。

naked call

表示函数无需保护现场(prolog)和恢复现场(epilog)的代码。

这在 vc++ 下不是通过关键字实现的,而是通过 __declspec(naked) 函数声明;gcc 下通过 __attribute__((naked))。

naked 标志跟 __inline 内联函数是不同的机制,不能一起使用。

关于函数名修饰规则

编译器输出的函数名,在其他目标文件中引用该函数时使用。

C 语言采用上述规则,而 C++ 则采用另一套规则,该规则详尽描述了函数原型,因此显得有些复杂。

但是,在 C++ 中可以使用 extern "C" 来要求以 C 编译器的方式来编译和链接,这也会以 C 的方式来修饰函数名。

在编写可移植的代码时,常用以下代码段来实现这一目标:

#ifdef __cplusplus

extern "C" {

#endif

// code

#ifdef __cplusplus

}

#endif /* end of __cplusplus */

拓展阅读

转载至链接:https://my.oschina.net/tridays/blog/1930040

java函数调用约定_函数调用约定 (cdecl stdcall)相关推荐

  1. java进出栈_JVM函数调用:Java出入栈

    JVM函数调用:Java出入栈 JVM函数调用:Java出入栈 目录 局部变量表 索引复用 垃圾回收 栈数据区 栈上分配 线程作为系统运算调度的最小单位,在JVM中线程的行为体现就是函数调用,函数调用 ...

  2. JAVA通过调用数据库函数调用存储过程

    下面将举一个通过数据库函数来调用存储过程: 创建数据库函数存储过程 CREATE OR REPLACE FUNCTION stu_proc ( v_id IN NUMBER ) RETURN VARC ...

  3. python函数调用时所提供的参数可以是常量_元组的元素不能修改,一般作为参数传递给函数调用,或是从函数调用除获得参数时,保护其内容不被外部接口修改和破坏。( )_学小易找答案...

    [单选题]设 且 存在,则 ________ [单选题]下列论断中,( )是准确的 [单选题]当常数 --时,曲线 与 相切 [判断题]在列表中可以嵌套另一个列表.( ) [填空题]常用的编程思想有面 ...

  4. 动态链接库、名字修饰约定、调用约定

    调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议.这种协议规定了该语言的函数中的参数传送方式.参数是否可变和由谁来处理堆栈等问题.不同的语言定义了不 ...

  5. 关于delphi中的register, pascal, cdecl, stdcall, safecall

    最近用delphi写了个软件.所以特此也转篇文章,以留作记录吧. 1...http://blog.csdn.net/yfy_47/article/details/6572374 注: 使用错误,或者在 ...

  6. JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系

    文章目录 Pre 示例demo 总体关系 代码示例论证 反汇编 Pre JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器 中我们探讨了线程栈中的内部结构 ,大家 ...

  7. Java计算时间差_传统的SimpleDateFormat类

    Java计算时间差_传统的SimpleDateFormat类 SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd ...

  8. JAVA异常使用_每个人都曾用过、但未必都用得好

    JAVA异常使用_每个人都曾用过.但未必都用得好 一.抛出异常 vs. 返回错误代码 有人说"Well, an exception is a goto.",但也有人言"m ...

  9. 学习笔记:Java 并发编程①_基础知识入门

    若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...

最新文章

  1. 戴森最新吸尘器,竟用上了无人车和宇宙飞船黑科技
  2. 手机客户端连接linux
  3. springmvc项目在启动完成之后执行一次方法_SpringMVC运行原理
  4. Java 中如何模拟真正的同时并发请求?
  5. 详解在 Linux 启动时,如何自动执行命令或脚本
  6. 浏览器上请求URL的全部过程
  7. 远程办公(2)-重新定义“雇佣关系”:交易成果,而不是时间
  8. 使用idea的maven插件自动打jar包
  9. PHP_APC+Ajax实现的监视进度条的文件上传
  10. 冗余链路中STP协议的工作过程以及二期STP收敛速度优化方案介绍
  11. 证券业大数据与人工智能发展现状与应用趋势
  12. C语言中的数据类型及输出格式
  13. 计算机酷炫桌面,电脑桌面还能这么酷炫?!打破次元壁的桌面管理软件
  14. 一周技术思考(第22期)-编程的基本礼节
  15. 《小岛经济学》八、金本位的破灭、房地产的泡沫
  16. Error: The apk for your currently selected variant (app-release-unsigned.apk) is not signed. Please
  17. dotnetfx35.exe
  18. 使用vs2010生成64位的dll文件
  19. LeetCode 974. 和可被 K 整除的子数组 | Python
  20. Android高工:细说 Android 多线程,探究原理知其所以然

热门文章

  1. VS2019中出现【Windows SDK】找不到 Windows SDK 版本10.0.18362.0的解决办法
  2. 拼多多开店一定要知道
  3. 【李沐AI自学】线性神经网络
  4. QUIC的那些事 | 包类型及格式
  5. Java中[xxx:xxx,aaa:aaa]格式字符串解析
  6. 爱奇艺移动端网络优化实践分享:网络请求成功率优化篇
  7. 如何培养孩子的读写能力?猿辅导老师建议分5个阶段
  8. 汉诺塔——python递归
  9. 有状态和无状态(@stateless/@stateful)
  10. 计算机软件打开时提示管理员,win7安装软件时老提示管理员权限,什么消除?-win7管理员身份,怎么以管理员身份运行win7...