(转载)函数调用方式比较

【图解函数调用过程】【转载】 函数调用是编程语言都有的概念,也许你听说过函数调用栈,但是大家都知道函数调用是如何完成的吗?我们为什么要了解这个过程:对于程序运行机制中的数据结构和实现的了解,对自己开发程序有着启发作用碰到一些疑难杂症的时候,比如函数栈溢出了或者函数栈破坏了,如何从蛛丝马迹中寻找问题的原因。了解栈溢出可能带来的危害,黑客也许会利用栈溢出的漏洞进行攻击。这篇博文我们一起来对函数调用的过程进行探究。 阅读详情

对于各种的call,看看汇编的结果很清楚,  例如对于函数:  
  void   func(int   a,   int   b,   int   c,   int   d)   {   }  
  使用函数如下  
  int   main()  
  {  
  func(1,   2,   3,   4);  
  }   

1.如果函数func是__cdecl(默认调用方式),调用时情况如下  
  int   main()  
  {  
  //参数从右到左压栈  
  push   4  
  push   3  
  push   2  
  push   1  
  call   func  
  add   esp   0x10   //调用者恢复堆栈指针esp,4个参数的大小是0x10(4x4)  
  }  
   
  2.如果函数func是__stdcall,调用时情况如下  
  int   main()  
  {  
  //参数从右到左压栈  
  push   4  
  push   3  
  push   2  
  push   1  
  call   func  
                //恢复堆栈指针由被调用者func负责,方法是"ret   0x10"  
  }  
   
  3.如果函数func是__pascal,调用情况如下  
  int   main()  
  {  
  //参数从左到右压栈  
  push   1  
  push   2  
  push   3  
  push   4  
  call   func  
  //恢复堆栈指针由被调用者func负责,方法是"ret   0x10"  
  }   
    
 4.如果函数func是__fastcall,调用情况如下  
  int   main()  
  {  
  //参数先用ecx,   edx,   eax传递,然后再压栈  
  //不进栈  
  //(不知为什么,帮助中写的是从左到右传递的,  
  //是不是错了,还是BCB6和BCB5的不一样)  
  push   4  
  mov   ecx 3  
  mov   edx 2  
  mov   eax 1  
  call   func  
  //恢复堆栈指针由被调用者func负责,方法是"ret   0x04",  
  //因为只进栈一个参数,其余用寄存器传递,所以用ret   0x04恢复  
  }   
    
   

函数调用规范__cdecl和__stdcall的区别一目了然(表格形式)

Posted on Tuesday, May 24, 2005 3:23 PM #C & C++ href="http://blog.bcchinese.net/happyjet/Services/Pingback.aspx" rel="pingback" />

 

__cdecl

 

 

__stdcall

 

C 和 C++ 程序的缺省调用规范

 

为了使用这种调用规范,需要你明确的加上 __stdcall (或 WINAPI )文字。即 return-type __stdcall function-name[(argument-list)]

 

 

在被调用函数 (Callee) 返回后,由调用方 (Caller) 调整堆栈。

 

1. 调用方的函数调用

                                         

2. 被调用函数的执行

 

3. 被调用函数的结果返回

 

4. 调用方清除调整堆栈

                                                                

 

在被调用函数 (Callee) 返回前,由被调用函数 (Callee) 调整堆栈。图示:

 

1. 调用方的函数调用

 

2. 被调用函数的执行

 

3. 被调用函数清除调整堆栈

 

4. 被调用函数的结果返回                                                           

 

因为每个调用的地方都需要生成一段调整堆栈的代码,所以最后生成的文件较大。

 

 

因为调整堆栈的代码只存在在一个地方(被调用函数的代码内),所以最后生成的文件较小。

 

函数的参数个数可变(就像 printf 函数一样),因为只有调用者才知道它传给被调用函数几个参数,才能在调用结束时适当地调整堆栈。

 

 

函数的参数个数不能是可变的。

 

对于定义在 C 程序文件中的输出函数,函数名会保持原样,不会被修饰。

对于定义在 C++ 程序文件中的输出函数,函数名会被修饰, MSDN 说 Underscore character (_) is prefixed to names . 我实际测试( VC4 和 VC6 )下来发现好像不是那么简单。

可通过在前面加上 extern “C” 以去除函数名修饰。也可通过 .def 文件去除函数名修饰。

 

不论是 C 程序文件中的输出函数还是 C++ 程序文件中的输出函数,函数名都会被修饰。

对于定义在 C 程序文件中的输出函数, An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.

对于定义在 C++ 程序文件中的输出函数,好像更复杂,和 __cdecl 的情况类似。

好像只能通过 .def 文件去除函数名修饰。

 

 

_beginthread 需要 __cdecl 的线程函数地址

 

 

_beginthreadex 和 CreateThread 需要 __stdcall 的线程函数地址

 

 

两者的参数传递顺序都是从右向左。

为了让 VB 可以调用,需要用 __stdcall 调用规范来定义 C/C++ 函数。请参看Microsoft KB153586 文章:How To Call C Functions That Use the _cdecl Calling Convention。

当你 LoadLibrary 一个 DLL 文件后, 把 GetProcAddress 取得的函数地址传给上面三个线程生成函数时,请务必确认实际定义在 DLL 文件的输出函数符合调用规范要求。否则,编译成 Release 版后运行,可能会破坏堆栈,程序行为不可预测。

VC 中的相关编译开关:/Gd /Gr /Gz。另外,VC6中新增加的 /GZ 编译开关可以帮你检查堆栈问题。

我也是初学者,若有不对的地方、可以补充的地方,请指教。谢谢。  

 

(补充)汇编语言视点的比较文章: Intel x86 Function-call Conventions - Assembly View


<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
C++函数调用运算符重载 函数调用运算符重载 函数调用运算符 () 也可以重载 由于重载后使用的方式非常像函数的调用,因此称为仿函数 仿函数没有固定写法,非常灵活 示例: class MyPrint { public: void operator()(string text) { cout << text << endl; } }; void test01() { //重载的()操作符 也称为仿函数 MyPrint myFunc; myFunc("hello world"); } 阅读详情

相关推荐

Hermes Dashboard Web 端部署完整说明

通过反向代理(nginx)使用公网域名访问时,会遇到 Host 头校验、CORS 跨域、WebSocket 连接拒绝三个核心问题。本文档记录了完整的源码修改方案和部署步骤。确保 nginx 主配置加载了 WebSocket map(宝塔默认为。路径的公开访问(无需登录),其他路径仍受 Cookie 认证保护。Hermes Dashboard 默认绑定。访问站点时会先弹出浏览器密码框,输入用户。在 nginx 反向代理配置中的。环境变量动态读取允许的域名。nginx 配置中已添加。

大白菜代码的博客 805

linux动态库调用优先级,Linux动态库搜索路径优先级问题 第二个人的理解

Linux动态库搜索路径优先级问题 第二个人的理解发布时间:2008-05-05 21:09:39来源:红联作者:zisxvdmc作者:annight E-mail:annightzhao@gmail.com5月5日今天学习LINUX的动态库的搜索优先级当运行GCC,将先把程序经过编译器生成 .o文件,该文件不能直接运行,需再次生成可执行文件,才可被系统运行。如果程序中涉及到调用库函数时候,这时...

weixin_30366435的博客 557

ArduPilot移植到自定义硬件:完整指南

详解如何将ArduPilot成功移植到自定义硬件平台,涵盖环境搭建、代码配置与调试技巧。无论是初学者还是进阶开发者,都能快速掌握ArduPilot在不同硬件上的适配方法,提升开发效率。

weixin_28931449的博客 638

浅谈——程序执行和函数的调用

以前写一个程序,只知道编译,在无错后就直接运行了,然后看看结果是不是自己想要的,结果对了然后就啥也不管了,如果错了就只会一行一行的看自己的代码,看看问题在哪(大多数时候,看了半天也不知道问题在哪),经过最近的学习了解,才知道一个程序的运行也不是我所想的那么简单。 初步了解了一个程序的运行包括了,预处理,编译,汇编,链接等过程,这些过程下面又分了很多的子过程,要想真正的去了解他,要学习的还有很多。

haishark的博客 1689

告别机床‘卡顿’!用C语言在STM32上实现连续小线段速度前瞻(附开源代码)

本文详细介绍了如何在STM32上使用C语言实现工业级连续小线段速度前瞻控制器,解决机床运动控制中的卡顿问题。通过轻量级算法框架设计和混合精度计算策略,显著提升加工效率和表面质量。文章包含开源代码和实战案例,帮助开发者快速掌握速度前瞻规划算法在嵌入式系统中的应用。

weixin_42571738的博客 186

Unity中URP实现水体效果(泡沫)

在上篇文章中,我们实现了水体的深度。在这篇文章中,我们来使用上篇文章采样后的深度图来实现水中的泡沫效果。

楠溪泽岸的博客 3489

关于函数的定义、调用和执行

认识函数(定义-执行-销毁(执行空间)) 1-先定义 2-再调用 在JS函数中,数值是先赋值,再进预解析 function fn(a){ console.log(a); function a(){} } fn(100);//ƒ a(){} 说明在函数中,先赋值,再进行预解析 一个不销毁的执行空间 在函数执行空间中,函数代码执行结束,则执行空间销毁,函数内的变量也会销毁; 若想要保存函数内的变量,怎么办? 答:在函数内返回一个引用数据类型(数组、对象、函数),并且

weixin_42943920的博客 946

ZED双目相机环境配置

ZED SDK 安装文件夹中有一个 Python 脚本(get_python_api.py),可以自动检测操作系统、CUDA 和 Python 版本并下载相应的预编译 Python API 包(pyzed)。安装SDK成功后,我们进入ZED SDK文件夹中的tools子文件夹,运行ZED Explorer.exe 以及 ZED Depth Viewer.exe,查看ZED相机是否能正常启用工作。在本例中,我们简单地检索ZED相机的序列号:打开 ZED相机,然后打印其序列号,然后关闭相机。

qq_53545309的博客 2137

函数的定义与调用

函数的定义与调用

m0_64332867的博客 377

〔重庆理工大学〕计算机网络实验指导书【实验九 直连路由,静态路由,默认路由配置】

本实验指导书介绍了直连路由、静态路由和默认路由的配置方法。主要内容包括:1)路由器基础知识,包括直连路由、静态路由和动态路由三种路由生成方式;2)路由度量值与匹配顺序,解释了不同路由类型的优先级;3)实验任务分为三个部分:直连路由的查看分析、静态路由的配置以及默认路由的配置,详细说明了配置步骤和命令。实验要求通过模拟器搭建网络环境,完成路由配置使PC间能够互通。实验旨在帮助学生掌握不同路由类型的工作原理和配置方法,适用于简单的网络环境。

Pretty Boy Fox的博客 1056

Python爬虫实战:如何爬取12306列车信息

本文介绍了如何使用Python编写爬虫,抓取12306列车信息。我们讲解了如何分析12306的列车数据接口,如何发送HTTP请求,解析返回的JSON数据,并将数据保存到本地文件中。我们还讨论了如何绕过反爬虫机制,如使用随机User-Agent和设置请求延时。通过这个实战项目,你应该掌握了如何爬取并解析来自公共API的数据,同时提高了你的爬虫技能。这些技能不仅适用于12306列车信息抓取,也可以广泛应用于其他需要抓取JSON数据的网站。

2201_76125261的博客 1922

C语言函数的调用——比较两个数的大小

目录 一、先写好框架 二、然后定义我们需要的变量 三、这里就要写函数的部分 四、函数部分写完了,但是还一个地方,要值得注意 一、常规方法比较大小 二、指针操作比较大小 今天我们要写的是用调用函数的方法来 比较两个数字的大小 我们先看看程序的运行效果 一、先写好框架 #include<stdio.h> void main() { } 二...

欢迎来到Gorit的博客 6万+

btstack ble ota开发笔记(2)-mcuboot移植

紧接上一篇文章,要实现一个完整的ota demo,除了实现ota image的传输通道外,还需要“bootloader”这个角色来帮我们实现ota image的校验、安全、引导以及启动,这里我选择开源的组件mcuboot,下面开始介绍mcuboot在stm32f4-discovery上的移植。首先估算下bootloader & application image的大小,确定好flash的分布情况,因为后续会涉及到flash的操作(读、写、擦除),为了方便程序的编写,各个image area在flash中的起

weixin_38177846的博客 2350

【翻译、转载】【转载】LLM 的函数调用与 MCP

函数调用是一种机制,允许 LLM 根据用户输入识别它需要什么工具以及何时调用它。LLM 接收来自用户的提示。LLM 决定它需要的工具。程序员实现程序来接受来自 LLM 的工具调用请求,并准备一个函数调用。函数调用(带有参数)被传递给将处理实际执行的后端服务。让我们快速看看实际操作!首先,我们定义一个工具函数。它使用yfinance库来获取指定股票代码的最新收盘价:【参考】# (示例 Python 代码,定义 get_stock_price 函数)

计算机视觉之光 1211

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【转载】SAP比较常用的几个接口方式及比较

1.PI - 信使中间件 (大公司多选择) 数据: SAP- PI- U8 U8- PI- SAP PI 底层用的还是webservice 技术 优点:实时性高; 可处理大数据(在调用PROXY 发送时 还可以分包处理); 有接口数据日志在PI系统; 缺点:PI 服务器+1; PI系统配置工作; 和每个外部系统都要做wsdl配置; 2. RFC - 函数 (小公司 / 简单业务场景使用) ...

hubaichun的专栏 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

函数调用的三种方式

'''1 什么是调用函数 函数名(...)即调用函数,会执行函数体代码,直到碰到return结束或者一直运行完毕所有代码2 为何要调用函数 用函数的功能3、函数调用分为三种形式 max2(1,2) res=max2(3000,2000) * 12 res=max2(max2(1000,2000),3000)函数定义时 在代码块之前加上“”“         ...

ZHOUXIN0426的博客 3374

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

函数调用的4种方式

一、函数调用的4种模式 1、函数调用 function foo() { alert('hello'); } foo();注意:this 专指全局对象 window 2、方法调用 // 定义一个函数 var foo = function() { alert("我是一个函数么?"); }; // 将其赋值给一个对象 var...

weixin_33716154的博客 1025

函数调用栈比较有意思

函数调用栈比较有意思作者:liigo原文链接:http://blog.youkuaiyun.com/liigo/archive/2006/12/23/1456938.aspx转载请注明出处:http://blog.youkuaiyun.com/liigo 昨天和海洋一块研究了下函数调用栈,顺便写两句。不足或错误之处请包涵!理解调用栈最重要的两点是:栈的结构,EBP寄存器的作用。首先要认识到这样两个

周狼赤壁的技术博客 2540

函数指针的初始化以及函数调用的三种方式

【c和指针学习笔记】函数指针的初始化以及函数调用的三种方式 2015年09月28日 21:29:20zyh_helen阅读数 3331 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/ZongYinHu/article/details/48790555 看如下代码,然后思考如下几个问题:(9+条消息)【c和指针学习笔记】函数指针的...

weixin_41632560的博客 1972

【转载】函数调用方式--__thiscall调用方式和__cdecl,__stdcall有什么区别

原文链接:https://blog.youkuaiyun.com/u014269285/article/details/80503180 函数调用方式–__thiscall调用方式和__cdecl,__stdcall有什么区别 首先,__thiscall是关于类的一种调用方式,它与其他调用方式的最大区别是: __thiscall对每个函数都增加了一个类指针参数 class aa { void bb(i...

gclome的博客 265

中断触发方式的比较(转载)

中断触发方式的比较 在前后台系统或者带有OS的系统,中断处理程序是相对比较难的,对系统的性能影响比较大。在带有OS的系统中,中断作为一个异步事件,还可以引发任务调度。在带有OS的系统中我们经常会关闭中断,而在ISR中我们...

weixin_30745553的博客 1254

转载——比较器的原理

比较器的原理

m0_37327467的博客 4655

优快云转载的方式

起意        看到一篇不错的博客,想转载但是不会(没有转载键),网搜发现没有Chrome浏览器的详细转载办法 实践 检查。在喜欢的博客页面右键(用快捷键ctrl+shift+I也行只是比较难找到相应想要的html码)选择“检查...

weixin_57619565的博客 112

IT168转载问题解决情况,以及本人博客转载方式

与IT168编辑联系之后,目前文章已添加原文链接,并且答应以后的各类转载都会符合协议。这个结局比较令人满意。此外,我想在这里详细谈一下这方面的一些做法。 转载方式简介 首先,请注意每篇文章下方都有一个Licence链接,如下: 点击上面的图标或链接“共享 2.5 中国大陆”,将会进入...

chuifuhuo6864的博客 114

Ruby中的各种比较方式对比

Ruby中设计了很多种比较方式,所有对象都能进行==、!=、===、<=>、eql?、equal?这几种比较。此外,当实现了<=>之后,如果还include了Comparable之后,就会自动获得<=、<、==、>=、>、between?这几个比较方法。 这些比较方法的定义位置和意义分别如下。 在BasicObject中定义了: ==:比较内容是...

weixin_30315723的博客 355
上一篇: 读史记——刘敬叔孙通列传第三十九(1)
下一篇: 找工作(1)——微软
llmlx
博客等级 码龄23年 15粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值