_declspec(dllimport)
请问为什么C++里面生成dll,如果接口用import定义,最后生成的dll里面还是会找到该函数符号?,这个不应该是导入才有的吗
__declspec(dllimport)
和__declspec(dllexport)
是Microsoft Visual C++编译器使用的特定关键字,用于在DLL(动态链接库)和使用这些库的代码之间设置链接规格。
在一般的应用中,这两个关键字是如何工作的呢?
当你在创建一个DLL时,你会使用__declspec(dllexport)
来标记你想要公开的函数、变量或者对象。这样,编译器就知道这些符号需要被导出,而不是仅在DLL内部使用。
在另一边,你使用DLL的代码应该使用__declspec(dllimport)
来标记那些在DLL中定义的函数、变量或者对象。这告诉编译器这些符号实际上是在别处定义的,编译器将生成正确的代码来从DLL中调用或访问这些符号。
现在,关于你的问题——即使你用__declspec(dllimport)
标记了一个符号,但在最终的DLL中仍然能找到该符号。这是因为__declspec(dllimport)
只是告诉编译器这个符号是在别处定义的,但并不阻止你在当前的DLL中重新定义或者实现它。如果你在编译DLL的代码中实际实现了这个符号,那么它仍然会出现在最终的DLL中。
如果你不希望这个符号出现在最终的DLL中,你需要确保在编译DLL的代码中没有实现它,而只是在头文件中声明它,并使用__declspec(dllimport)
进行标记。
不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。
那我就来试验一下,假定,你在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中的类,在你的cpp中,没有定义SIMPLEDLL_EXPORT
所以此时对于cpp来说,.h中就相当于class SimpleDLLClass{};
这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。
修改上述代码,将m_nValue改为static变量:
///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:
DLL_EXPORT static int m_nValue;
};
///SimpleDLLClass.cpp
#include "SimpleDLLClass.h"
SimpleDLLClass::SimpleDLLClass()
{
static m_nValue=0;
}
SimpleDLLClass::~SimpleDLLClass()
{
}
int SimpleDLLClass::m_nValue=0;
改完之后,再去LINK一下,这时会发现,结果是LINK告诉你找不到这个m_nValue。
正好对应MSDN上说的若想使用DLL 中使用的静态变量,则必须使用 __declspec(dllimport) 声明才行。
所以需要将代码改为:
///SimpleDLLClass.h
#ifdef SIMPLEDLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
原来dllimport是为了更好的处理类中的静态成员变量的
如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。
总结一下:对于.h文件,定义了SIMPLEDLL_EXPORT
,其内部的DLL_EXPORT
为__declspec(dllexport)
,对于cpp没有定义SIMPLEDLL_EXPORT
,所以在没有修改时,没有DLL_EXPORT
没有定义,而修改成static变量后,DLL_EXPORT
为__declspec(dllimport)
_declspec(dllexport)与_declspec(dllimport)都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。主要区别在于,dllexport是在这些类、函数以 及数据的申明的时候使用。用过表明这些东西可以被外部函数使用,即(dllexport)是把DLL中的相关代码(类,函数,数据)暴露出来为其他应用程 序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。而 dllimport关键字是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL内部代码(类,函数,全局变量)时,只需要在程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才 使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。
__declspec(dllexport) int add(int a, int b)
{
return a+b;
}
__declspec(dllexport) int sub(int a, int b)
{
return a-b;
}
可以使用工具查看dll文件内封装起来的函数,查看结果如下:
上图中ordinal为函数的序号,hint表示提示码,rva是表示函数在dll中的地址,name表示函数名。
我们声明的导出函数为add和sub,但发现name中的函数名并非是add和sub
原因:
这是因为在C++中为了支持函数重载,在编译器进行编译链接时,会将函数名和形参一起进行考虑,往往会去篡改函数的名字,按照自己定义的法则去改变函数的名字。这也导致了一个问题:不同的C++的编译器定义的改名的法则并不相同,函数名各不相同。从而使得在调用dll内函数时,会有找不到函数入口的问题
https://blog.csdn.net/ljianhui/article/details/9005935
https://www.cnblogs.com/Dageking/p/4054863.html