C++-dllexport与dllimport介绍和使用

dllexport与dllimport

dllexport与dllimport存储级属性是微软对C和C++的扩展,可用于从dll中导入或导出函数、数据、对象(objects)

语法

__declspec( dllimport ) declarator
__declspec( dllexport ) declarator

这些属性显式地定义了dll提供给客户端的接口,客户端可以是一个可执行文件或者另一个dll。dllexport声明的使用免去了模块定义(.def)文件的使用,def文件至少包含相关导出函数的声明。
dllexport暴露的是函数的修饰名(decorated name)1。如果想避免函数名修饰,使用C函数或者使用extern "C"2修饰C++函数。
示例代码:

//DLL项目头文件
#pragma once
#include 

#ifdef DLLTEST_EXPORTS
# define DLL_API _declspec(dllexport)
# else
# define DLL_API _declspec(dllimport)
#endif // DLLTEST_EXPORTS

class DLL_API DLLClass
{
public:
    int add(int a, int b);
    std::string add(std::string, std::string);

    static int static_var;
};

extern DLL_API int a;
extern "C" DLL_API int aa;

namespace DLLNamespace
{
extern DLL_API int b;

}

DLL_API int addFunc(int, int);
extern "C" DLL_API int addFunc2(int, int);
//DLL项目CPP
#include "DLLClass.h"

int DLLClass::add(int a, int b)
{
    return a + b;
}

std::string DLLClass::add(std::string s1, std::string s2)
{
    return s1 + s2;
}

int DLLClass::static_var = 3;

int a = 1;
int aa = 11;

namespace DLLNamespace
{
int b = 2;
}

int addFunc(int a, int b)
{
    return a + b;
}

int addFunc2(int a, int b)
{
    return a + b;
}
//测试代码
#include 
#include "DLLClass.h"

using namespace std;

int main()
{
    DLLClass obj;
    cout << obj.add(1, 1) << endl;
    cout << obj.add("hello ", "world!") << endl;
    cout << "a: " << a << endl;
    cout << "b: " << DLLNamespace::b << endl;
    cout << "static member: " << DLLClass::static_var << endl;
    cout << addFunc(1, 1) << endl;
    cout << addFunc2(1, 1) << endl;
}

以下是dumpbin查看dll导出的所有定义

 ordinal hint RVA      name

          1    0 0001126C ??4DLLClass@@QAEAAV0@$$QAV0@@Z = @ILT+615(??4DLLClass@@QAEAAV0@$$QAV0@@Z)
          2    1 00011050 ??4DLLClass@@QAEAAV0@ABV0@@Z = @ILT+75(??4DLLClass@@QAEAAV0@ABV0@@Z)
          3    2 00020004 ?a@@3HA = ?a@@3HA (int a)
          4    3 0001151E ?add@DLLClass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V23@0@Z = @ILT+1305(?add@DLLClass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V23@0@Z)
          5    4 000112AD ?add@DLLClass@@QAEHHH@Z = @ILT+680(?add@DLLClass@@QAEHHH@Z)
          6    5 0001103C ?addFunc@@YAHHH@Z = @ILT+55(?addFunc@@YAHHH@Z)
          7    6 0002000C ?b@DLLNamespace@@3HA = ?b@DLLNamespace@@3HA (int DLLNamespace::b)
          8    7 00020000 ?static_var@DLLClass@@2HA = ?static_var@DLLClass@@2HA (public: static int DLLClass::static_var)
          9    8 00020008 aa = _aa
         10    9 0001148D addFunc2 = @ILT+1160(_addFunc2)

我们可以看到,重载函数实现的原理就是使用函数名修饰(4和5),使用extern "C"修饰的函数或变量导出定义时的名字与原函数名或变量名相同(9和10)

参考:

  1. https://docs.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?redirectedfrom=MSDN&view=msvc-170

  1. C++函数存在name mangling,其目的就是为了给重载的函数不同的签名,以避免调用时的二义性 ↩︎

  2. 被extern "C"修饰的变量和函数是按照C语言方式编译和连接的,不会进行函数名修饰 ↩︎

你可能感兴趣的:(C++,c++,开发语言,dll,动态链接库)