【原创+整理】简述何为调用约定,函数导出名以及extern C
2015-07-29 17:09
218 查看
何为调用约定
调用约定指的是函数在调用时会按照不同规则,翻译成不同的汇编代码。这和参数的压栈顺序和栈的清理方式相关,也就是说不同的调用约定,这些方式会做相应改变。一般编译器是以默认的调用约定编译一份代码,但当一个项目使用不同调用约定的库会产生链接错误。
何为函数导出名
同一个函数,在不同的编译器编译出来的符号名是不一样的,程序目标文件链接的时候不知道源程序的函数名,而是通过目标文件(.obj)中寻找相应的函数符号表。在下面中会指出不同调用约定对应的函数导出名。
三种调用约定
(1)__fastcall
特点:快
参数传递方式:前两个参数-寄存器,剩余参数-栈(右到左)
栈的清理者:被调函数
函数导出名:
按C的编译方式:@函数名@参数字节数
按C++的编译方式:
(2)__cdecl
特点:C语言调用约定,文件比__stdcall大
参数传递方式:栈(右到左)
栈的清理者:调用者
函数导出名:
按C的编译方式:_函数名
按C++的编译方式:规则同下面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。
(3)__stdcall
特点:标准调用约定, Pascal程序的缺省调用方式,通常用于Win32 Api中
参数传递方式:栈(右到左)
栈的清理者:被调用者
函数导出名:
按C的编译方式:_函数名@参数字节数
按C++的编译方式:
1)、以"?"标识函数名的开始,后跟函数名;
2)、函数名后面以"@@YG"标识参数表的开始,后跟参数表;
3)、参数表以代号表示:
X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;
4)、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
5)、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。
上面这段代码,源文件后缀必须是.c,同时使用windows系统的dumpbin工具即可获得对应目标文件的内容。
View Code
C编译的函数如何在C++中使用
解决办法是采用extern "C"修饰符。使用方法是,把该修饰符添加到调用约定必须是__cdecl的C函数前,如DriverEntry,windows驱动函数入口函数规定为_DriverEntry@8,因此用C++编译器
一些库是用C编译而成的,而在C++平台想要使用这些库,我们可以这样引入C库函数头文件
参考链接:
/article/5207917.html
/article/2577929.html
http://www.2cto.com/kf/201405/301756.html
本文链接:/article/7044976.html
调用约定指的是函数在调用时会按照不同规则,翻译成不同的汇编代码。这和参数的压栈顺序和栈的清理方式相关,也就是说不同的调用约定,这些方式会做相应改变。一般编译器是以默认的调用约定编译一份代码,但当一个项目使用不同调用约定的库会产生链接错误。
何为函数导出名
同一个函数,在不同的编译器编译出来的符号名是不一样的,程序目标文件链接的时候不知道源程序的函数名,而是通过目标文件(.obj)中寻找相应的函数符号表。在下面中会指出不同调用约定对应的函数导出名。
三种调用约定
(1)__fastcall
特点:快
参数传递方式:前两个参数-寄存器,剩余参数-栈(右到左)
栈的清理者:被调函数
函数导出名:
按C的编译方式:@函数名@参数字节数
按C++的编译方式:
(2)__cdecl
特点:C语言调用约定,文件比__stdcall大
参数传递方式:栈(右到左)
栈的清理者:调用者
函数导出名:
按C的编译方式:_函数名
按C++的编译方式:规则同下面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。
(3)__stdcall
特点:标准调用约定, Pascal程序的缺省调用方式,通常用于Win32 Api中
参数传递方式:栈(右到左)
栈的清理者:被调用者
函数导出名:
按C的编译方式:_函数名@参数字节数
按C++的编译方式:
1)、以"?"标识函数名的开始,后跟函数名;
2)、函数名后面以"@@YG"标识参数表的开始,后跟参数表;
3)、参数表以代号表示:
X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;
4)、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
5)、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。
上面这段代码,源文件后缀必须是.c,同时使用windows系统的dumpbin工具即可获得对应目标文件的内容。
//把获得obj函数导出名,存储到d:\\1.txt文件 dumpbin OBJ文件路径/all /rawdata:none > d:\\1.txt //获得汇编代码,存储到d:\\2.txt dumpbin OBJ文件路径/disasm d:\\2.txt
View Code
C编译的函数如何在C++中使用
解决办法是采用extern "C"修饰符。使用方法是,把该修饰符添加到调用约定必须是__cdecl的C函数前,如DriverEntry,windows驱动函数入口函数规定为_DriverEntry@8,因此用C++编译器
一些库是用C编译而成的,而在C++平台想要使用这些库,我们可以这样引入C库函数头文件
extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistry) { //do something return STATUS_SUCCESS; }
#ifdef __cplusplus extern"C" { #endif #include<NTDDK.h> #ifdef __cplusplus } #endif
参考链接:
/article/5207917.html
/article/2577929.html
http://www.2cto.com/kf/201405/301756.html
本文链接:/article/7044976.html
相关文章推荐
- ZigZag Conversion
- HDOJ1272~小希的迷宫~并查集
- POJ 1157 LITTLE SHOP OF FLOWERS(动态规划)
- button的内边距
- 【Java】日志知识总结和常用组合配置(commons-logging,log4j,slf4j,logback)
- Linux下的内核测试工具——perf使用简介
- com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte
- 奇偶数间隔排序问题
- Android 单元测试——AndroidTestCase
- Python PIL 图片添加水印
- hadoop yarn 配置
- iOS编程——Swift实现一个3D可旋转的立方体(可做菜单页)
- 【剑指Offer面试题】 九度OJ1514:数值的整数次方
- swing布局
- 全排列
- ASP.NET WEB API简介
- 用.net 2.0(或.net 3.5)开发的程序在.net 4.0的环境中运行的解决方案
- Win10怎么删除自带应用?Win10使用命令卸载自带应用教程
- linux C++ 面向对象线程类封装
- 地址获得经纬度