Chinaunix首页 | 论坛 | 博客
  • 博客访问: 70681
  • 博文数量: 10
  • 博客积分: 1431
  • 博客等级: 上尉
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-15 19:45
文章分类
文章存档

2011年(1)

2010年(6)

2009年(3)

我的朋友

分类: C/C++

2011-01-16 19:14:21

    这种用法只是微软的格式,在Linux或者Unix编程中是没有这种用法的。
    如果在我们自己的应用程序中,希望使用某个动态链接库中的函数,那么就最好使用 __declspec(dllimport)来声明这一个函数是被导入的。
    当然,在动态链接库的实现函数部分(准确来说,是函数的声明部分,当然在头文件中声明,然后再源文件中实现),使用了__declspec(dllexport)表示该函数是被导出的。
    在头文件中,使用某个编译预处理符号,就不用在应用程序和库文件中重复声明。
    于是,使用库文件的应用程序和该库文件都使用一个共同的头文件。
    这个头文件可能像下边这样:
#ifdef _EXPORTING
    #define API_DECLSPEC    __declspec(dllexport)
#else
    #define API_DECLSPEC    __declspec(dllimport)
#endif
   
   API_DECLSPEC  void func();
  
  
   当然,在实现库的工程中,使用_EXPORTING编译预处理符号。我们的应用程序中就不使用这个_EXPORTING编译预处理符号了。

    开始我就说明了,这种用法只是在Windows下边的特色。
    下边是从网上copy来。参考了很多资料,在此不一一注明。
    不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它十分清楚函数是否在 DLL 中,因此可以生成跳过间接级别的代[来源:GameRes.com]码,而在跨 DLL 边界的函数中通常存在这些间接代码。
    但是,必须使用__declspec(dllimport) 才能导入 DLL 中使用的变量。
    如果有正确的 .DEF 文件 EXPORTS 节,则不需要 __declspec(dllexport)。添加 __declspec(dllexport) 是为了提供不使用 .DEF 文件从 .EXE 或 .DLL 导出函数的简单方法。
    模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件。如果不使用 __declspec(dllexport) 关键字导出 DLL 的函数,则 DLL 需要 .def 文件。
    .def 文件必须至少包含下列模块定义语句:
    1.文件中的第一个语句必须是 LIBRARY 语句。此语句将 .def 文件标识为属于 DLL。LIBRARY 语句的后面是 DLL 的名称。链接器将此名称放到 DLL 的导入库中。
    2.EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。通过在函数名的后面加上 @ 符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从 1 到 N,其中 N 是 DLL 导出函数的个数。
    例如,包含实现链表的代码的 DLL 看上去可能像下面这样:

    LIBRARY   LINKTEST
    EXPORTS
    Insert        @1
    Delete        @2
    NodeNumber    @3
    IsNodeExsit   @4
提示:
    如果希望优化 DLL 文件的大小,请对每个导出函数使用 NONAME 属性。使用 NONAME 属性时,序号存储在 DLL 的导出表中而非函数名中。如果导出许多函数,这样做可以节省相当多的空间。
    其实__declspec(dllexport)的作用就是让编译器按照某种预定的方式(前面大致解释了这种方式的规则)来输出导出函数及变量的符号,而def文件则是自己为每一个函数和变量指定导出符号,所以def是一个非自动化,手工很强的方式,不是特殊情况的话,实在没有必要浪费这些时间。
    还有一个问题,就是使用def会把调用方式和__declspec(dllexport)的作用全部覆盖掉,所以还需要自己处理调用方式不同产生的错误。
    一般使用def文件的情况是你需要使用运行时加载,并且需要使用GetProcAddress函数获得函数地址,这个函数需要直接指明函数产生的导出符号,而可以自己指定导出符号的方式就是使用def。
    
      使用 .DEF 文件的优缺点(zz)
      在 .def 文件中导出函数使您得以控制导出序号。当将附加的导出函数添加到 DLL 时,可以给它们分配更高的序号值(高于任何其他导出函数)。当您进行此操作时,使用隐式链接的应用程序不必与包含新函数的新导入库重新链接。这非常重要,例如,在设计将由许多应用程序使用的第三方DLL 时。可以通过添加附加功能不断地增强 DLL,同时确保现有应用程序继续正常使用新的 DLL。MFC DLL 是使用 .def 文件生成的。
      使用 .def 文件的另一个优点是:可以使用 NONAME 属性导出函数,该属性仅将序号放到 DLL 的导出表中。对具有大量导出函数的 DLL,使用NONAME 属性可以减小 DLL 文件的大小。有关编写模块定义语句的信息,请参见模块定义语句的规则。有关序号导出的更多信息,请参见按序号而不是按名称从 DLL 导出函数。
      使用 .def 文件的主要缺点是:在 C++ 文件中导出函数时,必须将修饰名放到 .def 文件中,或者通过使用外部“C”用标准 C 链接定义导出函数,以避免编译器进行名称修饰。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用相同版本的 Visual C++ 生成的,这样调用应用程序中的修饰名才能与 DLL 的 .def 文件中的导出名相匹配。
 
 

 
阅读(2550) | 评论(1) | 转发(0) |
0

上一篇:extern int errno 可能会引发的问题

下一篇:没有了

给主人留下些什么吧!~~

ffee092011-01-17 10:48:16

年底将近推荐个数码网站http://clic.gs/1IJk想入手的摄友可以去看看,我刚入手了部无敌兔的。