dllimport与dllexport作用与区别
我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。但是,MSDN文档里面,对于__declspec(dllimport)的说明让人感觉有点奇怪,先来看看MSDN里面是怎么说的:
不使用
__declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport)
使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL
中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport)
才能导入 DLL 中使用的变量。
初看起来,这段话前面的意思是,不用它也可以正常使用DLL的导出库,但最后一句话又说,必须使用
__declspec(dllimport) 才能导入 DLL
中使用的变量这个是什么意思??
那我就来试验一下,假定,你在DLL里只导出一个简单的类,注意,我假定你已经在项目属性中定义了
SIMPLEDLL_EXPORT
SimpleDLLClass.h
#ifdef SIMPLEDLL_EXPORT
#define
DLL_EXPORT __declspec(dllexport)
#else
#define
DLL_EXPORT
#endif
class DLL_EXPORT
SimpleDLLClass
{
public:
SimpleDLLClass();
virtual
~SimpleDLLClass();
virtual getValue() { return
m_nValue;};
private:
int
m_nValue;
};
SimpleDLLClass.cpp
#include
"SimpleDLLClass.h"
SimpleDLLClass::SimpleDLLClass()
{
m_nValue=0;
}
SimpleDLLClass::~SimpleDLLClass()
{
}
然后你再使用这个DLL类,在你的APP中include
SimpleDLLClass.h时,你的APP的项目不用定义 SIMPLEDLL_EXPORT 所以,DLL_EXPORT
就不会存在了,这个时候,你在APP中,不会遇到问题。这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。但我们也没有遇到变量不能正常使用呀。那好,我们改一下SimpleDLLClass,把它的m_nValue改成static,然后在cpp文件中加一行
int
SimpleDLLClass::m_nValue=0;
如果你不知道为什么要加这一行,那就回去看看C++的基础。
改完之后,再去LINK一下,你的APP,看结果如何,结果是LINK告诉你找不到这个m_nValue。明明已经定义了,为什么又没有了??肯定是因为我把m_nValue定义为static的原因。但如果我一定要使用Singleton的Design
Pattern的话,那这个类肯定是要有一个静态成员,每次LINK都没有,那不是完了? 如果你有Platform
SDK,用里面的Depend程序看一下,DLL中又的确是有这个m_nValue导出的呀。
再回去看看我引用MSDN的那段话的最后一句。
那我们再改一下SimpleDLLClass.h,把那段改成下面的样子:
#ifdef SIMPLEDLL_EXPORT
#define
DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
__declspec(dllimport)
#endif
再LINK,一切正常。原来dllimport是为了更好的处理类中的静态成员变量的,如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。
_declspec(dllexport)与_declspec(dllimport)
都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。主要区别在于,dllexport是在这些类、函数以
及数据的申明的时候使用。用过表明这些东西可以被外部函数使用,即(dllexport)是把DLL中的相关代码(类,函数,数据)暴露出来为其他应用程
序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。而
dllimport关键字是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL内部代码(类,函数,全局变量)时,只需要在
程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才
使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。
_declspec(dllexport)与_declspec(dllimport)是相互呼应,只有在DLL内部用dllexport作了声明,才能
在外部函数中用dllimport导入相关代码。实际上,在应用程序访问DLL时,实际上就是应用程序中的导入函数与DLL文件中的导出函数进行链接。而
且链接的方式有两种:隐式迎接和显式链接。
隐式链接是指通过编译器提供给应用程序关于DLL的名称和DLL函数的链接地址,面在应用程序中不需要显式地将DLL加载到内存,即在应用程序中使用dllimport即表明使用隐式链接。不过不是所有的隐式链接都使用dllimport。
显式链接刚同应用程序用语句显式地加载DLL,编译器不需要知道任何关DLL的信息
dllimport与dllexport作用与区别的更多相关文章
- VS下 dllimport与dllexport作用与区别
我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是C++的类的话 ...
- 基于Java的打包jar、war、ear包的作用与区别详解
本篇文章,小编为大家介绍,基于Java的打包jar.war.ear包的作用与区别详解.需要的朋友参考下 以最终客户的角度来看,JAR文件就是一种封装,他们不需要知道jar文件中有多少个.cla ...
- ubuntu sudo update与upgrade的作用及区别
ubuntu sudo update与upgrade的作用及区别 入门linux的同志,刚开始最迫切想知道的,大概一个是中文输入法,另一个就是怎么安装软件.本文主要讲一下LINUX安装软件方面的特点. ...
- BeanFactory和ApplicationContext的作用和区别
BeanFactory和ApplicationContext的作用和区别 作用: 1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责be ...
- .h头文件和.c文件的作用和区别
.h头文件和.c文件的作用和区别 在小工程中,.h的作用没有得到充分的使用,在大工程中才能充分体现出.h文件的作用. .h和.c文件都是代码.头文件好处有: 一:头文件便于共享,只需要添加一句“inc ...
- (转)Java 之 FileReader FileInputStream InputStreamReader BufferedReader 作用与区别
Java 之 FileReader FileInputStream InputStreamReader BufferedReader 作用与区别 ava.io下面有两个抽象类:InputStream和 ...
- java打包jar,war,ear包的作用、区别
java的打包jar,war,ear包的作用,区别,打包方式. a) 作用与区别 i. jar: 通常是开发时要引用通用(JAVA)类,打成包便于存放管理 ii. war ...
- 环境变量配置的作用和区别:Path、Classpath、JAVA_HOME
环境变量配置的作用和区别:Path.Classpath.JAVA_HOME 一个是零时配置,另一个是永久性配置. 零时配置的方法: 打开cmd窗口——>输入set命令,回车——>输入set ...
- (转)从一道面试题彻底搞懂hashCode与equals的作用与区别及应当注意的细节
背景:学习java的基础知识,每次回顾,总会有不同的认识.该文系转载 最近去面试了几家公司,被问到hashCode的作用,虽然回答出来了,但是自己还是对hashCode和equals的作用一知半解的, ...
随机推荐
- JavaScript学习笔记(一)对象和属性
对象属性的使用 JavaScript中的所有变量都可以当做对象使用,除了null和undefined. false.toString(); // 'false' [1, 2, 3].toString( ...
- Google机器学习教程心得(一)
Hello world Google Machine Learning Recipes 1 官方中文博客 http://chinagdg.org/2016/03/machine-learning-re ...
- python----脚本文件的头部写法。
#!/usr/bin/python #这里主要是为了指明python脚本解释器的路径. #!coding:utf-8#这个是为了告知python脚本文件解释器,此脚本的字符集. import sys ...
- SQL Server 数据库的自动选项
自动选项影响SQL Server 可能会自动进行的操作,所有的这些都是bool值,值为on 或off 1. auto_close: 当这个为on 时.数据库在最后一个用户退出后完全关闭,这样数据库就不 ...
- python学习day2(二)
1.类与对象的关系 对于Python,一切事物都是对象,对象基于类创建 type是获取类的 dir是获取这个类里面的成员 2.int内部功能介绍 bit_length:返回表示当前数字占用的最少位数: ...
- ISO和UDF光盘格式、扩展ISO9660----Joliet和Romeo文件系统
ISO和UDF光盘格式.扩展ISO9660----Joliet和Romeo文件系统 刻录DVD盘,当文件大于2G的时候,Nero会提示NERO选文件时提示无法刻录这么大的文件,请转换格式.这到底是怎么 ...
- getopt vs getopts
getopt示例 #!/bin/bash aflag=no args=`getopt a: $@` ]; then echo 'Usage: ...' exit fi set -- $args ] d ...
- 2014上半年acm总结(1)(入门+校赛)
大一下学期才开始了acm,不得不说有一点迟,但是acm确实使我的生活充实了很多,,不至于像以前一样经常没事干= = 上学期的颓废使我的c语言学的渣的一笔..靠考前突击才基本掌握了语法 寒假突然醒悟, ...
- Gradient boosting
Gradient boosting gradient boosting 是一种boosting(组合弱学习器得到强学习器)算法中的一种,可以把学习算法(logistic regression,deci ...
- openstack中文文档
http://www.openstack.cn/p392.html openStack Hacker中文文档 http://docs.mirantis.com/fuel-dev/develop/a ...