函数的调用约定方式及函数的名称修饰符

函数的调用约定方式及函数的名称修饰符

ID:5266428

大小:353.98 KB

页数:7页

时间:2017-12-07

函数的调用约定方式及函数的名称修饰符_第1页
函数的调用约定方式及函数的名称修饰符_第2页
函数的调用约定方式及函数的名称修饰符_第3页
函数的调用约定方式及函数的名称修饰符_第4页
函数的调用约定方式及函数的名称修饰符_第5页
资源描述:

《函数的调用约定方式及函数的名称修饰符》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库

1、几乎每种编程语言都有函数的概念,而作为函数,就一定有参数的概念;一般来说,参数的传递是通过栈来实现的,栈是一种先入后出的数据结构,使用Push()把参数压入栈中,使用Pop()把参数弹出栈,而且Push()和Pop()必须成对出现。现在称为标准调用的就是PASCAL语言的调用方式:反序压栈,正序出栈;这样做的确有好处,因为压栈行为是编译器编译好的(编译时行为),虽然麻烦,但是只在编译阶段做一次,而出栈行为是程序实际运行时的调用行为(运行时行为),需要反复多次执行,使用正序的参数(正序出栈),对被调函数来说,

2、处理上方便不少;而Windows使用的调用方式跟PASCAL语言的调用方式是一样的,所以,以前老的C程序员编写Windows程序时需要使用关键字PASCAL来明确指出使用PASCAL的调用规则,现在一般不再使用PASCAL关键字了,而使用__stdcall说明符,表示使用的是标准调用;使用C/C++语言开发软件的程序员经常碰到这样的问题:有时候是程序编译没有问题,但是链接的时候总是报告函数不存在(经典的LNK2001错误),有时候是程序编译和链接都没有错误,但是只要调用库中的函数就会出现堆栈异常。这些现象通

3、常是出现在C和C++的代码混合使用的情况下或在C++程序中使用第三方的库的情况下(不是用C++语言开发的),其实这都是函数调用约定(CallingConvention)和函数名修饰(DecoratedName)规则惹的祸。函数调用约定方式决定了函数参数入栈的顺序,是由调用者函数还是被调用函数负责清除栈中的参数等问题,而函数名修饰规则决定了编译器使用何种名字修饰方式来区分不同的函数,如果函数之间的调用约定不匹配或者名字修饰不匹配就会产生以上的问题。本文分别对C和C++这两种编程语言的函数调用约定和函数名修饰规

4、则进行详细的解释,比较了它们的异同之处,并举例说明了以上问题出现的原因。*******************************************************************************一、函数的调用约定方式(CallingConvention):有很多种方式,常见的有__cdecl、__stdcall、__fastcall,C++的编译器还支持__thiscall方式,不少的C/C++编译器还支持nakedcall方式;*********************

5、**********************************************************1.__cdecl方式(编译器的命令行参数是/Gd):__cdecl是C/C++编译器默认的函数调用约定;所有非C++成员函数和那些没有用__stdcall或__fastcall声明的函数都默认是__cdecl方式。函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数。由于每次函数调用都要由编译器产生清除/还原堆栈的代码,所以使用__cdecl方式编译出来的程序比使用__stdcall

6、方式编译出来的程序要大很多,但是__cdecl调用方式是由调用者函数负责清空栈中的函数参数,所以,__cdecl方式支持可变参数,比如printf和Windows的APIwsprintf就是__cdecl调用方式;对于C函数,__cdecl方式的名字修饰符约定是在函数名称前面添加一个下划线;对于C++函数,除非特别使用extern"C",C++函数使用不同的名字修饰符;2.__stdcall方式(编译器的命令行参数是/Gz):_stdcall是Pascal程序的缺省调用方式,通常用于Win32Api中,大多

7、数Windows的API也是__stdcall调用约定。__stdcall函数调用约定将函数参数从右向左入栈,除非使用指针或引用类型的参数,所有参数采用传值方式传递,由被调用函数负责清除栈中的参数。对于C函数,__stdcall的名称修饰方式是在函数名称前面添加下划线,在函数后面添加@符号和函数参数所占用的内存字节大小;例如:_function_name@number;3.__fastcall方式(编译器的命令行参数是/Gr):__fastcall函数调用约定在可能的情况下使用寄存器传递参数,通常是前两个D

8、WORD类型的参数或较小的参数使用ECX和EDX寄存器传递,其余参数按照从右向左的顺序入栈,被调用函数在返回之前负责清除栈中的参数。编译器使用两个@来修饰函数的名字,后面跟十进制数字表示函数参数列表所占用的内存字节大小;比如:@function_name@number;需要注意的是:__fastcall函数调用约定在不同的编译器上可能有不同的实现;比如:16位的编译器和32位的编译器,另外,在使用内嵌汇编代码时,

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。