__declspec(dllimport)的作用
是时候总结一下__declspec(dllimport)的作用了。可能有人会问:__declspec(dllimport)和__declspec(dllexport)是一对的,在动态链接库中__declspec(dllexport)管导出,__declspec(dllimport)管导出,就像一个国家一样,有出口也有进口,有什么难理解的呢?这是一种很自然的思路,开始我也是这样理解。
但是在两年前的一个项目中,我发现不用__declspec(dllimport)似乎也可以。比如现在我新建一个使用共享MFC DLL的规则DLL工程:DllDlg。然后我新建两个文件:DllApi.h和DllApi.cpp。DllApi.h作为接口文 件,DllApi.cpp作为实现文件。
接着在DllApi.h声明一个函数:
- __declspec(dllexport) void HelloWorld();
- __declspec(dllexport) void HelloWorld();
在DllApi.cpp写这个函数的实现:
- void HelloWorld()
- {
- AfxMessageBox(_T("HelloWorld"));
- }
- void HelloWorld()
- {
- AfxMessageBox(_T("HelloWorld"));
- }
这样外部的应用程序或dll就能调用HelloWorld函数。这里要特别提醒的是:有些网友说要把DllApi.h中的__declspec(dllexport) void HelloWorld();改为__declspec(dllimport) void HelloWorld();才能提供给外部调用,实际上这并不需要,这个我已经测试过。从那时我就产生一个疑问:照这样,像类似下面的:
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
是不是就只剩下一种作用:让外部调用者看得更自然些,知道哪些接口是自己工程需要导入的?__declspec(dllimport)是不是一点实际作用都没有呢?这个疑问一直盘旋在我的脑海。直到最近,我在CSDN论坛上发了一个帖子:
__declspec(dllimport) 的作用到底在哪里呢?
总结了各位大虾的发言,特得出如下结论:
1. 在导入动态链接库中的全局变量方面起作用:
使用类似
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
可以更好地导出dll中的全局变量,比如按照的宏,可以在dll中这样导出全局变量:
- API_DECLSPEC CBtt g_Btt;
- API_DECLSPEC CBtt g_Btt;
然后在调用程序这样导入:
- API_DECLSPEC CBtt g_Btt;
- API_DECLSPEC CBtt g_Btt;
当然也可以使用extern关键字,比如在dll中这样导出全局变量:
- CBtt g_Btt;
- CBtt g_Btt;
然后在调用程序这样导入:
- extern CBtt g_Btt;
- extern CBtt g_Btt;
但据说使用__declspec(dllimport)更有效。
2. __declspec(dllimport)的作用主要体现在导出类的静态成员方面,
比如在动态链接库中定义这样一个导出类:
- class __declspec(dllexport) CBtt
- {
- public:
- CBtt(void);
- ~CBtt(void);
- public:
- CString m_str;
- static int GetValue()
- {
- return m_nValue;
- }
- private:
- static int m_nValue;
- };
- class __declspec(dllexport) CBtt
- {
- public:
- CBtt(void);
- ~CBtt(void);
- public:
- CString m_str;
- static int GetValue()
- {
- return m_nValue;
- }
- private:
- static int m_nValue;
- };
照上面这样声明,外部虽然可以使用CBtt类,但不能使用CBtt类的GetValue函数,一使用就会出现无法解析的外部符号 "public: static int CBtt::m_nValue" (?m_nValue@CBtt@@2HA)。只有如下声明才能使用CBtt类的GetValue函数:
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
- class API_DECLSPEC CBtt
- {
- public:
- CBtt(void);
- ~CBtt(void);
- public:
- CString m_str;
- static int GetValue()
- {
- return m_nValue;
- }
- private:
- static int m_nValue;
- };
- #ifdef _EXPORTING
- #define API_DECLSPEC __declspec(dllexport)
- #else
- #define API_DECLSPEC __declspec(dllimport)
- #endif
- class API_DECLSPEC CBtt
- {
- public:
- CBtt(void);
- ~CBtt(void);
- public:
- CString m_str;
- static int GetValue()
- {
- return m_nValue;
- }
- private:
- static int m_nValue;
- };
3. 使用隐式使用dll时,不加__declspec(dllimport)完全可以,使用上没什么区别,只是在生成的二进制代码上稍微有点效率损失。
a、 不加__declspec(dllimport)时,在使用dll中的函数时,编译器并不能区别这是个普通函数,还是从其它dll里导入的函数,所以其生 成的代码如下:
call 地址1
地址1:
jmp 实际函数地址
b、有 __declspec(dllimport)时,编译器知道这是要从外部dll导入的函数,从而在生成的exe的输入表里留有该项,以便在运行 exe,PE载入器加载exe时对输入地址表IAT进行填写,这样生成的代码如下:
call dword ptr[输入表里哪项对应的内存地址] (注意:现在就不需要jmp stub了)。这里
有兴趣的朋友可以参看《编译原理》和 PE文件格式。
4.使用__declspec(dllimport)体现了语言的一种对称美,比如虽然!true就是表示false,但是我们还是需要false这个关键字,这里体现了一种对称美。
在此特别感谢CSDN的众位大侠:superdiablo、wltg2001、ccpaishi、jszj、WizardK、hurryboylqs、jingzhongrong、jameshooo、glacier3d、winnuke、starnight1981、laiyiling、yang79tao、ForestDB、zhouzhipen、lxlsymbome、Beyond_cn。
参考文献:
1. __declspec(dllimport) 到底有什么用?
from: http://blog.csdn.net/clever101/article/details/5421782
__declspec(dllimport)的作用的更多相关文章
- __declspec(dllexport) 和 __declspec(dllimport)的作用
operatordll.h #include <iostream> #ifndef _WIN32 #define DLL_EXPORT#else #ifdef OPERATORDLL_EX ...
- __declspec(dllimport)与__declspec(dllexport)作用总结
参考自:http://bbs.csdn.net/topics/330169671 __declspec(dllexport):导出符号,也就是定义需要导出函数的dll中给导出函数的函数声明前面加上导出 ...
- __declspec(dllimport)
我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是C++的类的话 ...
- extern "C" __declspec(dllexport) __declspec(dllimport) 和 def
原文:extern "C" __declspec(dllexport) __declspec(dllimport) 和 def 前面的extern "C" _ ...
- __declspec(dllexport) & __declspec(dllimport)
__declspec(dllexport) 声明一个导出函数,是说这个函数要从本DLL导出.我要给别人用.一般用于dll中 省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是 ...
- 浅谈__declspec(dllexport)和__declspec(dllimport)
__declspec(dllimport)和__declspec(dllexport)经常是成对的,在动态链接库中__declspec(dllexport)导出dll中的成员,__declspec(d ...
- 动态链接库(dll) __declspec(dllimport) __declspec(dllexport)
一. __declspec(dllexport) Microsoft 在 Visual C++ 的 16 位编译器版本中引入了 __export,使编译器得以自动生成导出名并将它们放到一个 .lib ...
- 【转载】extern "C" __declspec(dllexport) __declspec(dllimport) 和 def
转自:http://www.cppblog.com/FateNo13/archive/2009/08/03/92052.html 前面的extern "C" __declspec ...
- 【转载】 __declspec(dllexport) 和__declspec(dllimport)
转自:http://www.cppblog.com/Dutyboy/archive/2010/11/15/133699.html __declspec(dllexport) __declspec( ...
随机推荐
- 基于stm32f103zet6的FAT16文件系统学习1(初识FAT16)
有了之前读写block的基础之后,准备弄个文件系统,之前没有接触过这东西,所以有很多都晕晕的,但是看到fat的源代码之后还是挺有信心的,因为之前一直过uboot,所以这个文件当然是小巫见大巫了.首先来 ...
- KEIL CRACK及 0xFD Bug修正方法
0xFD Bug是keil编译器中始终存在,而又从未得到官方修复的一个BUG!!! BUG描述:当C源代码中使用了汉字等非ASCII字符,而此字符的编码又恰好包含了大于或等于0xFD的字节时,这个字节 ...
- WPF笔记(2.2 DockPanel)——Layout
原文:WPF笔记(2.2 DockPanel)--Layout 读完了这一节,发现DockPanel就是过去winform中的Dock属性.原来的Dock属性是子控件设置,而其父亲级别不用设置.现在W ...
- 关于在Reshaper中添加代码模板代码段
http://www.cnblogs.com/tristinjet/archive/2009/08/19/1550203.html 去 tools->模板中进行模板编辑设置
- ubuntu下配置安装conky
由于默认的conky配置不好看,于是下载了一些配置,网上一抓一大把. 首先 sudo apt-get install conky-all 然后下载想要的配置文件,下载下来的是压缩文件,解压就行了,解 ...
- UESTC_邱老师选妹子(二) 2015 UESTC Training for Dynamic Programming<Problem I>
I - 邱老师选妹子(二) Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Su ...
- hdu 4502 吉哥系列故事——临时工计划_简单dp
题意: 俗话说一分钱难倒英雄汉,高中几年下来,吉哥已经深深明白了这个道理,因此,新年开始存储一年的个人资金已经成了习惯,不过自从大学之后他不好意思再向大人要压岁钱了,只能把唯一的希望放到 ...
- IOS拷贝文件到沙盒
- (void)copyFileFromResourceTOSandbox { //文件类型 NSString * docPath = [[NSBundle mainBundle] pathForRe ...
- Beauty of Array(思维)
Beauty of Array Time Limit: 2 Seconds Memory Limit: 65536 KB Edward has an array A with N integ ...
- 忘记root密码修改方法
好吧,不想重新装(那耗费的时间真心伤不起…),找修改root密码的方法,结果还真找到了… 首先在虚拟机启动时,在Grub界面按“e”进入编辑 在linux /vmlinuz那行后面添加“init=/b ...