自定义C/C++ dll导出后函数名为乱码(如@func@@YGXHX@Z)原因以及解决方案
2017-10-16 14:51
302 查看
1,现象:
自定义C/C++ dll,编译无错误,另一程序使用动态调用方法,加载dll正常,但是调用函数时使用各种方法无法成功。
使用dll查看工具,发现函数名为func和乱码的组合,如下图:
2, 原因查找:
各方查找原因,发现原因并不是有的帖子说的要在编译dll的头文件中加入 extern "C"
extern "C"只是说明导出函数使用C编译器,不加extern "C"说明使用C++编译器规则。
两种规则区别如下:
(1)C编译器的函数名修饰规则
对于__stdcall调用约定,编译器和链接器会在输出函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,如果原始函数为func(),编译后变为_func@;
(2)C++编译器的函数名修饰规则
C++的函数名修饰规则内容更加丰富,包含函数名,返回值类型,参数类型等信息。
a, 不管__cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”开始
b, 后面紧跟函数的名字
再后面是参数表的开始标识和按照参数类型代号拼出的参数表。
c, 详细规则如下:__stdcall,参数表的开始标识是“@@YG”
__cdecl方式则是“@@YA”
__fastcall方式则是“@@YI”。
d, 参数表以代号表示:
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"代表一次重复;
参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
e, 参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。
extern "C"只解决了C和C++语方之间调用的问题(extern "C" 是告诉编译器,让它按C的方式编译),它只能用于导出全局函数这种情况 而不能导出一个类的成员函数。
同时如果导出函数的调用约定发生改变,即使使用extern "C",编译后的函数名还是会发生改变。
3. 正确方法
添加模块定义文件(def文件):
LIBRARY "dodll"
EXPORTS
test1 @ 1
test2 @ 2
同时以release模式输出
调用正常
自定义C/C++ dll,编译无错误,另一程序使用动态调用方法,加载dll正常,但是调用函数时使用各种方法无法成功。
使用dll查看工具,发现函数名为func和乱码的组合,如下图:
2, 原因查找:
各方查找原因,发现原因并不是有的帖子说的要在编译dll的头文件中加入 extern "C"
extern "C"只是说明导出函数使用C编译器,不加extern "C"说明使用C++编译器规则。
两种规则区别如下:
(1)C编译器的函数名修饰规则
对于__stdcall调用约定,编译器和链接器会在输出函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,如果原始函数为func(),编译后变为_func@;
(2)C++编译器的函数名修饰规则
C++的函数名修饰规则内容更加丰富,包含函数名,返回值类型,参数类型等信息。
a, 不管__cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”开始
b, 后面紧跟函数的名字
再后面是参数表的开始标识和按照参数类型代号拼出的参数表。
c, 详细规则如下:__stdcall,参数表的开始标识是“@@YG”
__cdecl方式则是“@@YA”
__fastcall方式则是“@@YI”。
d, 参数表以代号表示:
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"代表一次重复;
参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
e, 参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。
extern "C"只解决了C和C++语方之间调用的问题(extern "C" 是告诉编译器,让它按C的方式编译),它只能用于导出全局函数这种情况 而不能导出一个类的成员函数。
同时如果导出函数的调用约定发生改变,即使使用extern "C",编译后的函数名还是会发生改变。
3. 正确方法
添加模块定义文件(def文件):
LIBRARY "dodll"
EXPORTS
test1 @ 1
test2 @ 2
同时以release模式输出
调用正常
相关文章推荐
- eval()函数不安全的原因以及解决方案
- Web应用乱码(2)__原因以及解决方案详解
- VS2015用C++创建的动态库导出函数名乱码原因分析
- URL传参的中文乱码原因以及解决方案
- hive表数据导出到csv乱码原因及解决方案
- 2013年1月18日调试触发器“表发生了变化,触发器或函数不能读它”的出现原因,以及解决方案
- DLL(动态库)导出函数名乱码含义
- eclipse — Failed to load the JNI shared library”……\jvm.dll问题原因以及解决方案
- hive表数据导出到csv乱码原因及解决方案
- 读XML文件乱码的原因以及解决方案
- DLL(动态库)导出函数名乱码含义
- DLL导出函数方法以及动态调用
- C++28、 创建dll,导出单个函数以及导出类
- Cocos2d-x 实现地图滚动,解释缝隙产生的原因以及解决方案
- PB命令行——查看DLL导出函数
- dll导出命名空间下的c风格函数陷阱
- dll 导出函数名的那些事
- android studio中 R文件丢失可能的产生原因 以及解决方案
- curl获取网页内容出现乱码或为空的解决方案,另附curl_getinfo函数解析
- JSP数据库Tomcat 产生乱码解决方案总结及原因(转一)