• X264中的__declspec(dllimport)


    看到X264中的x264.h中用到了__declspec(dllimport),决定一探究竟。

    1. __declspec(dllimport)的作用

    我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。

    但是对__declspec(dllimport) 则了解不多。

    MSDN上的文档:不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。

    可以看到,x264里用到了__declspec(dllimport)声明的也都是一些全局变量,可见,“必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量”确实是这样的(除了全局变量,在C++中的类静态成员变量也需要__declspec(dllimport)声明)。

    全局变量:

    不用__declspec(dllimport)的话,存在一些问题

    #include <stdio.h>
    #pragma comment(lib,"dllTest.lib")
    extern int dllGlobalVar;
    int main(int argc, char *argv[])
    {
      printf("%d ", *(int*)dllGlobalVar);
      *(int*)dllGlobalVar = 1;
      printf("%d ", *(int*)dllGlobalVar);
      return 0;
    }

    特别要留意的是用extern int dllGlobalVar声明所导进的并不是DLL中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用DLL中的全局变量。这一点,从*(int*)dllGlobalVar可以看出。因此在采用这种方式引用DLL全局变量时,千万不要进行这样的赋值操纵:

    dllGlobalVar = 1;

    其结果是dllGlobalVar指针的内容发生变化,程序中以后再也引用不到DLL中的全局变量了。

    在应用工程中引用DLL中全局变量的一个更好方法是:

    通过_declspec(dllimport)方式导进的就是DLL中全局变量本身而不再是其地址了,笔者建议在一切可能的情况下都使用这种方式。

    #include <stdio.h>
    #pragma comment(lib,"dllTest.lib")
    
    extern int _declspec(dllimport) dllGlobalVar; //用_declspec(dllimport)导进
    
    int main(int argc, char *argv[])
    {
      printf("%d ", dllGlobalVar);
      dllGlobalVar = 1; //这里就可以直接使用, 无须进行强制指针转换
      printf("%d ", dllGlobalVar);
      return 0;
    }

    2. __declspec(dllimport)使用方法(最佳实践)

    另外,在写dll的时候,一般使用这样的头文件写法:

    #ifdef _EXPORTING
    #define API_DECLSPEC    __declspec(dllexport)
    #else
    #define API_DECLSPEC    __declspec(dllimport)
    #endif

    考虑一个情况:若DLL1.CPP是源,DLL2.CPP使用了DLL1中的函数,但同时DLL2也是一个DLL,也要输出一些函数供Client.CPP使用。那么在DLL2中如何声明所有的函数,其中包含了从DLL1中引入的函数,还包括自己要输出的函数。这个时候就需要同时使用__declspec(dllexport)__declspec(dllimport)了。前者用来修饰本dll中的输出函数,后者用来修饰从其它dll中引入的函数。

    在DLL1工程中定义DLL_DLL1_EXPORTS宏,DLL2工程中定义DLL_DLL2_EXPORTS宏即可。

    DLL1.h

    #ifdef DLL_DLL1_EXPORTS
    #define DLL_DLL1_API __declspec(dllexport)
    #else
    #define DLL_DLL1_API __declspec(dllimport)
    #endif
    
    DLL_DLL1_API void FuncInDll1(void);
    DLL_DLL1_API void FuncInDll1(int);

    DLL2.h

    #include"dll1.h"
    
    #ifdef DLL_DLL2_EXPORTS
    #define DLL_DLL2_API __declspec(dllexport)
    #else
    #define DLL_DLL2_API __declspec(dllimport)
    #endif
    
    DLL_DLL2_API void FuncInDll2(void);
    DLL_DLL2_API void FuncInDll2(int);

    在DLL2工程中,由于没有定义DLL_DLL1_EXPORTS宏,那DLL1中的函数正好用__declspec(dllimport)声明,符合要求。

    参考资料:http://topic.csdn.net/u/20100322/00/17389242-a3f7-46d1-992b-ae4c4e2976bb.html

                  http://social.microsoft.com/Forums/es-ES/visualcpluszhchs/thread/74a7065e-5ba9-4216-bcff-251cf0145655

                  http://www.blogjava.net/wxb_nudt/archive/2007/09/11/144371.html

     

  • 相关阅读:
    Qt 优雅的结束程序
    Qt QPainter实现按钮添加半透明图片
    Qt QTableModel联表显示
    C++ unique 里 类型为vector<vector<int>> 的比较函数
    用JavaScript实现的2048.
    Linux 脚本控制和计划任务
    Linux shell脚本分支循环函数笔记
    Linux shell脚本特殊符号笔记
    Linux shell脚本笔记
    Linux 内存磁盘管理命令笔记
  • 原文地址:https://www.cnblogs.com/xiongjiaji/p/2542957.html
Copyright © 2020-2023  润新知