VS2015用C++创建的动态库导出函数名乱码原因分析
2016-02-27 10:59
405 查看
在上一篇博客【在VS2015中用C++创建动态库并用C#调用】中提到,在C# DllImport导入C/C++编写的动态库时函数,要加上CallingConvention
= CallingConvention.Cdecl来指定入口点的调用约定。这是因为C/C++编写的动态库默认的入口点约定为_cdecl,而VS默认调用动态库时的约定为_winapi。
本文将重点介绍下这些入口点的调用约定,并以此来说明函数名乱码的真正原因,并且会在下一篇博客中详细说明如何创建一个可以被其它语言调用的动态库。
(1)按照【在VS2015中用C++创建动态库并用C#调用】博文中1到8步创建测试项目,但是步骤8中的DLLTest.h中添加函数Test1和Test2的导出形式前,不要加EXTERN_C。
(2)使用Dependency Walker查看导出的动态库DLL
从上图中可以看到导出的函数名都是乱码,此时可以在乱码上右击选择Undecorate C++ Functions,如下图:
此时函数名会自动变为你想要的函数名,如下图
(4)下面详细讲解下函数名乱码的原因
C++编译时函数名修饰约定规则:
__stdcall调用约定:
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"标识结束。
其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如
int Test1(char *var1, unsigned long)-----?Test1@@YGHPADK@Z
void Test2()-----"?Test2@@YGXXZ"
__cdecl调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。
__fastcall调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。
(5)由上面可以看出C/C++导出的动态库DLL默认的入口点调用约定为__cdecl调用约定,所以C#在调用时需加CallingConvention
= CallingConvention.Cdecl来指定入口点的调用约定
(6)通过在导出函数前加入EXTERN_C,可以将导出的函数名固定为你想要的函数名,更改入口点约定,让导出的动态库可以被其它语言调用,
请浏览下篇博客。
= CallingConvention.Cdecl来指定入口点的调用约定。这是因为C/C++编写的动态库默认的入口点约定为_cdecl,而VS默认调用动态库时的约定为_winapi。
本文将重点介绍下这些入口点的调用约定,并以此来说明函数名乱码的真正原因,并且会在下一篇博客中详细说明如何创建一个可以被其它语言调用的动态库。
(1)按照【在VS2015中用C++创建动态库并用C#调用】博文中1到8步创建测试项目,但是步骤8中的DLLTest.h中添加函数Test1和Test2的导出形式前,不要加EXTERN_C。
(2)使用Dependency Walker查看导出的动态库DLL
从上图中可以看到导出的函数名都是乱码,此时可以在乱码上右击选择Undecorate C++ Functions,如下图:
此时函数名会自动变为你想要的函数名,如下图
(4)下面详细讲解下函数名乱码的原因
C++编译时函数名修饰约定规则:
__stdcall调用约定:
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"标识结束。
其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如
int Test1(char *var1, unsigned long)-----?Test1@@YGHPADK@Z
void Test2()-----"?Test2@@YGXXZ"
__cdecl调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。
__fastcall调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。
(5)由上面可以看出C/C++导出的动态库DLL默认的入口点调用约定为__cdecl调用约定,所以C#在调用时需加CallingConvention
= CallingConvention.Cdecl来指定入口点的调用约定
(6)通过在导出函数前加入EXTERN_C,可以将导出的函数名固定为你想要的函数名,更改入口点约定,让导出的动态库可以被其它语言调用,
请浏览下篇博客。
相关文章推荐
- C语言实现logistic回归
- C++基础总结(1)--基本数据类型范围
- C++基础总结(1)--基本数据类型范围
- C++: 解释error: call of overloaded ‘abs(int)’ is ambiguous
- Java JNI调用c语言的dll测试
- c++ virtual
- C语言书籍推荐
- C++中的namespace
- C语言之基本算法09—各位全是a的数列之和
- C++笔记:1
- C++开发人脸性别识别教程(15)——搭建MFC框架启动摄像头
- 【C++】Accessor and Mutator Functions & 函数形参与类私有成员重名的解决方法
- Boost MPI scatter
- C++ DirectX 游戏开发初级视频教程 20 资源下载链接
- c++11对多线程的典型用法
- C++基础——1.变量和基本类型(基于c++11)
- C++模板板块
- C++ 2杈树 完整
- C++ 红黑树
- C++ 酒桶算法