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

 

posted @ 2012-06-09 11:35  igody  阅读(591)  评论(0编辑  收藏  举报