求救:有关C++函数导出函数的命名格式

tuyang 2004-04-08 09:52:19
在DLL时,如果使用C++的命名规则导出函数,那么就会在函数名称上添加若干字符,
比如:int Test2() 变成了:?Test2@@YAHXZ
请问对于添加的这些字符的命名规则是什么啊?以前见过csdn中有这样的总结,现在死活查不出来。


...全文
1141 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
tuyang 2004-04-26
  • 打赏
  • 举报
回复
谢谢各位了。
captainwh 2004-04-20
  • 打赏
  • 举报
回复
导出全局函数的话,为什么要用c++修饰呢
extern "C"
{
// your functions, 注意要设置调用约定__stdcall或__cdecl
}
用coff2omf转换一下引入库就可以在bcb里面使用了

导出c++类
先把你要导出的类的接口部分做成一个抽象基类:
class CMyClass
{
public:
virtual __stdcall Func1() = 0;
virtual __stdcall Func2() = 0;
};

class CMyClassImpl : public CMyClass //这是你要导出的功能实现
{
public:
virtual __stdcall Func1();
virtual __stdcall Func2();
};

注意成员函数一定要设置调用方式,__stdcall或__cdecl都可以

然后在dll中导出两个外部函数:
extern "C"
{
CMyClass* __stdcall New_MyClass();
void __stdcall Delete_MyClass(CMyClass *pObj);
}

在bcb中引入接口类和外部函数的声明,将引入库转换一下就可以用了
CMyClass *pObj = New_MyClass();
pObj->Func1();
pObj->Func2();
Delete_MyClass(pObj);

注意在CMyClass中,不可以有重载函数

rivershan 2004-04-17
  • 打赏
  • 举报
回复
。。。。。。。。。
itmaster 2004-04-17
  • 打赏
  • 举报
回复
DLL中调用约定和名称修饰(三)

2、C++编译时函数(非类成员函数)名称修饰

当函数使用__cdecl调用约定时,编译器进行以下工作:



1.以?标识函数名的开始,后跟函数名;

2.函数名后面以@@YA标识开始,后跟返回值和参数表;

3.当函数的返回值或者参数与C++类无关的时候,返回值和参数表以下列代号表示:

B:const

D:char

E:unsigned char

F:short

G:unsigned short

H:int

I:unsigned int

J:long

K:unsigned long

M:float

N:double

_N:bool

PA:指针(*,后面的代号表明指针类型,如果相同类型的指针连续出现,以0

代替,一个0代表一次重复)

PB:const指针

AA:引用(&)

AB:const引用

U:类或结构体

V:Interface(接口)

W4:enum

X:void

4、@@YA标识之后紧跟的是该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前。当函数的返回值或者参数与C++类无关的时候,其处理符合本条规则,否则按照5、6规则处理;

5、当函数返回值为某个类或带有const性质的类的时候,返回值的命名为:?A/?B+V+类名+@@(不带加号)。当函数返回值为某个类的指针/引用或者带有const性质的类的指针/引用的时候,返回值的命名为:PA/AA或者PB/AB+V+类名+@@(不带加号);

6、函数参数为某个类的时候,并且该参数所使用的类曾经出现过的话(也就是与函数返回值所使用的类相同或者与前一个参数使用的类相同),则该参数类型格式为:V+1+@(不带加号)。如果该参数所使用的类没有出现过的话,则该参数类型格式为:V+类名+@@(不带加号)。函数参数为某个类的指针/引用或者带有const性质指针/引用的时候,则该参数类型格式是在上述格式的基础上在V前面加上代表指针/引用类型或者带有const性质指针/引用类型的标识符(PA/AA或PB/AB);

7、参数表后以@Z标识整个名字的结束,如果该函数无参数,则以Z标识结束。



当函数使用__stdcall调用约定时,编译器所做工作的规则同上面的__cdecl调用约定,只是参数表的开始标识由上面的@@YA变为@@YG。



当函数使用__fastcall调用约定时,编译器所做工作的规则同上面的__cdecl调用约定,只是参数表的开始标识由上面的@@YA变为@@YI。

3、C++编译类及其成员函数时名称修饰

对于导出的C++类,仅能使用__cdecl调用约定。在编译器编译过程中,编译器会对C++类进行处理。如:class __declspec(dllexport) MyClass会被处理为class MyClass & MyClass::operator=(class MyClass const &)。在C++编译器对C++类进行名称修饰的时候,编译器进行以下工作:



1.以?标识函数名的开始,后跟?4+类名;

2.类名后面跟@@QAE标识,对于导出类来说这是固定的;

3.@@QAE后面跟AAV0@ABV0@,即引用类型标识符AA+V+0(重复的类的标识符)+@(不带加号)和const性质的引用AB+V+ 0(重复的类的标识符)+@(不带加号);

4.最后以@Z标识整个名字的结束。



对于导出的C++类中的成员函数(非构造函数和析构函数),可以使用不同的调用约定。当导出的C++类中的成员函数使用__cdecl调用约定时,编译器进行以下工作:



1.以?标识函数名的开始,后跟函数名+@+类名(不带加号);

2.之后以@@QAE标识开始,后跟返回值和参数表;

3.当函数的返回值或者参数与C++类无关的时候,返回值和参数表以下列代号表示:

B:const

D:char

E:unsigned char

F:short

G:unsigned short

H:int

I:unsigned int

J:long

K:unsigned long

M:float

N:double

_N:bool

PA:指针(*,后面的代号表明指针类型,如果相同类型的指针连续出现,以0

代替,一个0代表一次重复)

PB:const指针

AA:引用(&)

AB:const引用

U:类或结构体

V:Interface(接口)

W4:enum

X:void

4、@@QAE标识之后紧跟的是该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前。当函数的返回值或者参数与C++类无关的时候,其处理符合本条规则,否则按照5、6规则处理;

5、当函数返回值为当前类或带有const性质的当前类的时候,返回值的命名为:?A或?B+V+1+@@(不带加号)。当函数返回值为当前类的指针/引用或者带有const性质的当前类的指针/引用的时候,返回值的命名为:PA/AA或PB/AB+V+1+@@(不带加号);

6、当函数返回值为某个类或带有const性质的类的时候,返回值的命名为:?A/?B+V+类名+@@(不带加号)。当函数返回值为某个类的指针/引用或者带有const性质的类的指针/引用的时候,返回值的命名为:PA/AA或者PB/AB+V+类名+@@(不带加号);

7、函数参数为某个类的时候,并且该参数所使用的类曾经出现过的话(也就是当前要导出的类、与函数返回值所使用的类相同或者与前一个参数使用的类相同的类),则该参数类型格式为:V+1+@(不带加号)。如果该参数所使用的类不是当前要导出的类的话,则该参数类型格式为:V+类名+@@(不带加号)。函数参数为某个类的指针/引用或者带有const性质指针/引用的时候,则该参数类型格式是在上述格式的基础上在V前面加上代表指针/引用类型或者带有const性质指针/引用类型的标识符(PA/AA或PB/AB);

8、参数表后以@Z标识整个名字的结束,如果该函数无参数,则以Z标识结束。



当函数使用__stdcall调用约定时,编译器所做工作的规则同上面的__cdecl调用约定,只是参数表的开始标识由上面的@@YA变为@@YG。



当函数使用__fastcall调用约定时,编译器所做工作的规则同上面的__cdecl调用约定,只是参数表的开始标识由上面的@@YA变为@@YI。

4、C++编译导出数据时名称修饰

对于导出的数据,仅使用__cdecl调用约定。在C++编译器对C++类进行名称修饰的时候,编译器进行以下工作:



1.以?标识数据的开始,后跟数据名;

2.数据名后面以@@3标识开始,后跟数据类型;

3.当数据类型与C++类无关的时候,数据类型以下列代号表示:

B:const

D:char

E:unsigned char

F:short

G:unsigned short

H:int

I:unsigned int

J:long

K:unsigned long

M:float

N:double

_N:bool

PA:指针(*,后面的代号表明指针类型,如果相同类型的指针连续出现,以0

代替,一个0代表一次重复)

PB:const指针

AA:引用(&)

AB:const引用

U:类或结构体

V:Interface(接口)

W4:enum

X:void

4.如果数据类型是某个类的时候,数据类型的命名为:V+类名+@@(不带加号)。当数据类型为当前类的指针/引用或者带有const性质的当前类的指针/引用的时候,数据类型的命名为:PA/AA或PB/AB+V+类名+@@(不带加号);

5.最后,如果数据类型是const性质,则修饰名以B结尾。如果数据类型是非const性质,则修饰名以A结尾。

vcforever 2004-04-16
  • 打赏
  • 举报
回复
当使用__stdcall将c函数从DLL中输出时,Microsoft的c++编译器就会改变函数的名字,设置一个下划线,再加上一个@符号的前缀,后面跟一个数字,表示作为参数传递给函数的字节数。

例如:
__declspec(dllexport) LONG __stdcall ExportFunction (int i, int j);
编译器会将他改变成
_ExportFunction@8
薛定谔之死猫 2004-04-16
  • 打赏
  • 举报
回复
Here

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vccelng4/html/elgrfArgumentPassingandNamingConventions.asp?frame=true
rivershan 2004-04-16
  • 打赏
  • 举报
回复
name mangling。。。

C++中为了解决类似函数重载的问题而产生的机制~
每种编译器都有自己的name mangling机制~
http://www.csdn.net/Develop/read_article.asp?id=25141
xstring 2004-04-16
  • 打赏
  • 举报
回复
你不用管规则是什么

如果需要这些符号,在你的project属性中输出map文件就可以了,你可以看到所有的函数的这种名字。

如果你需要将这些符号换成可读的函数名
如:?Test2@@YAHXZ 换成 int Test2()

可以用这个API

DWORD UnDecorateSymbolName(
PCSTR DecoratedName,
PSTR UnDecoratedName,
DWORD UndecoratedLength,
DWORD Flags
);

这个API的Requirements
Windows NT/2000/XP: Included in Windows 2000 and later.
Redistributable: Requires DbgHelp.dll 5.0 or later on Windows NT 4.0 and Windows 95/98/Me.
Header: Declared in Dbghelp.h.
Library: Use Dbghelp.lib.
zming 2004-04-16
  • 打赏
  • 举报
回复
那你得去了解VTABLE了。
tuyang 2004-04-16
  • 打赏
  • 举报
回复
解释一下,上面提到的命名规则指的是C和C++在编译时附加到obj文件中的规则。按照C的规范,函数名称全部只是函数名,不带传入参数、返回值类型描述。而C++格式的编译后,就带有传入参数、返回值的描述了,通过哪些奇怪的字符来表示。我的问题就是这些字符具体对对应到那些类型。

我现在正在做一个关于异常处理的东西,当程序出现异常后,我做的模块可以将异常出现的现场写道文件中,以供后来分析。其中包括程序的源代码及行号等。

To zming: 好像不是我想要的。hehe....
zming 2004-04-16
  • 打赏
  • 举报
回复
int Test2() 变成了:?Test2@@YAHXZ
这是VC采用符号命名规则生成的。不用去管它,但按这种规则导出的DLL仅能由VC代码调用。如果要使DLL供其它代码调用,如C++ Build、Delphi等,则必须自己定义DEF文件。如果要使DLL供VB等代码调用,则除了自己定义DEF文件外,导出函数的参数也必须使用BSTR、VARIANT、SAFEARRAY这三种数据类型。
zming 2004-04-16
  • 打赏
  • 举报
回复
1、定义一个DEF文件,后缀名为.def

格式如下:

; xxx.def : Declares the module parameters. 注释行

; DLL的名称
LIBRARY "xxx.DLL"

; 需要导出的函数与全局变量
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllRegisterServer @3 PRIVATE
DllUnregisterServer @4 PRIVATE

2、将DEF文件加入到工程中。

3、重新编译工程。
legend-never-die 2004-04-16
  • 打赏
  • 举报
回复
咦,你需要知道这些做什么?

这个好像得看编译原理吧,我也不懂
tuyang 2004-04-16
  • 打赏
  • 举报
回复
看来这个问题是没有人知道了。真是痛苦。

15,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧