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 <string>

#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 <iostream>
#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语言方式编译和连接的,不会进行函数名修饰 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mrbone11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值