发信人: lofe ()感激生活(), 信区: BorlandDev
标  题: 动态链结函式库(Dynamic Linked Library)(7)
发信站: 哈工大紫丁香 (2000年08月30日19:53:10 星期三), 站内信件

C++ Builder的命名规则

   * 除了前面提到的 __declspec编译指令之外,在C++ Builder尚有几种修饰字会影
     响到函数的命名, 它们就是 __cdecl,__stdcall,__pascal,__fastcall四个
     修饰字。为了了解该修饰字对於函式命名的影响,我们可以用以下的程式来测试
     之:

#ifndef _DLLNAME01_H_
#define _DLLNAME01_H_
#ifndef DLLNAME
#define EXTERN __declspec(dllimport)
#else
#define EXTERN __declspec(dllexport)
#endif
EXTERN void DllName01(void);
EXTERN void _stdcall DllName02(void);
EXTERN void _cdecl DllName03(void);
EXTERN void _pascal DllName04(void);
EXTERN void _fastcall DllName05(void);
#endif

以上为程式的定义,同时我们可以在 .CPP档中撰写相对应的空函式,然後将其编译成
DLL档,再利用TDUMP.EXE或是VC++ 内的DUMPBIN.EXE来观察其内容,由於TDUMP会将函
式命名解码,反而会使混淆原来的名称,因此以下的输出是由DUMPBIN.EXE得来。
函式定义 DLL内的函式名 摘要说明

void DllName01(void) @DllName01$qv 因为是CPP程式码
void _stdcall DllName02(void) @DllName02$qqsv 所以函式名都被修
void _cdecl DllName03(void) @DllName03$qv 饰过。
void _pascal DllName04(void) @DLLNAME04$QV
void _fastcall DllName05(void) @DllName05$qqrv

   * 以上结果是否令你丈二金钢、摸不着头绪。这是因为我们的程式名称若以CPP为
     延伸名,C++Builder会以C++ 特有的命名方式来为函式命名,这种命名方式会在
     函式名称後加上其使用参数的性质,如参数类别等。这在C++ 中有一个特别的名
     称,叫做mangled name,这是一种为了要实作出多载函式所发出的命名规则。
     (注:在C++ 中Add(int) 和Add(double) 可以同时存在,因此必须在object
     code区分之)。同时这种命名方式由於各个编译器厂商使用的方式各不相同,因
     此在撰写DLL时要避免使用之。为了要避开以上问题,我们改以下列的宣告方
     式:

#define _DLLNAME01_H_
#ifndef DLLNAME
#define EXTERN __declspec(dllimport)
#else
#define EXTERN __declspec(dllexport)
#endif
extern "C" {
EXTERN void DllName011(void);
EXTERN void _stdcall DllName022(void);
EXTERN void _cdecl DllName033(void);
EXTERN void _pascal DllName044(void);
EXTERN void _fastcall DllName055(void);
};
#endif

其中extern "C" {...}; 是用来告诉编译器使用C的命名方式,不要使用C++
的mangled name。若是其中只有一个函式时,你可以直接以下列方式宣告之:

extern "C" void __stdcall ShowImage();

现在我们可以检视除去mangled name後的函式名称:
函式定义 DLL内的函式名 摘要说明

void DllName01(void) _DllName01 名称加底线
void _stdcall DllName02(void) DllName02 名称未变
void _cdecl DllName03(void) _DllName03 名称加底线
void _pascal DllName04(void) DLLNAME04 名称大写
void _fastcall DllName05(void) @DllName05 名称加@

以上我们可得知,在未加修饰字时和使用_cdecl修饰字时的名称是一样的。而
_pascal修饰字所产生的函式名则和16位元的标准DLL 函式名相同(这在VC++ 是不被
接受的),__fastcall的函式名称则加上 @。

其中在WIN32中使用最多的是 _stdcall修饰字,这也是你要撰写一个可以和其他语言
共同使用时所使用的修饰字,其次则为 __cdecl修饰字,这是用来传送不定参数型别
的函式如printf、sprintf等使用的。其馀两者几乎在DLL没有机会使用。

结论:由上可知,在C++Builder中撰写DLL时必须注意以下事项:
  1. 使用 __declspec(dllimport)及 __declspec(dllexport)的标准型式。
  2. 注意C++ 的函式名称编码(mangled name)。
  3. 注意修饰字的使用。除非使用不定参数的函式,否则必使用 __stdcall修
饰字。
(4) 不要把 __declspec的使用和 __stdcall混淆了。此二者并没有绝对的相关性。
即使是程式老手都可能栽在此处,切记,切记!
怎麽样,在看完了以上的介绍後,是否有晃然大悟的感觉。在了解以上的规则後,今
後不论在撰写或是使用DLL时遭遇连结的问题时,应该难不倒你吧!

最後,我们将标准的DLL宣告方式列於後,以加深你的印象:

#ifndef _SHOWIMG_H_
#define _SHOWIMG_H_
#ifndef IMGDLL
#define EXTERN __declspec(dllimport)
#else
#define EXTERN __declspec(dllexport)
#endif
extern "C" EXTERN void __stdcall ShowImage(void);
#endif

--
真正的程序员用C, 聪明的程序员用什么?——Inprise工具!

欢迎光临BorlandDev版,探讨Inprise编程

           独孤九剑的最高境界是不拿剑
           编程的最高境界是无所谓工具

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: malacs.hit.edu.cn]
※ 修改:·lofe 於 08月30日20:01:45 修改本文·[FROM: malacs.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.658毫秒