河南网站建设优化,wordpress 迁移 新目录,成都网站建设推广服务,赣州网上商城系统1. 动态库和导出和导入
1.1 动态库的导出
1. 创建新项目
新建新项目#xff0c;选择动态链接库#xff08;DLL#xff09;。 填写项目名称#xff0c;并选择项目保存的路径#xff0c;然后点击创建。 创建完成后#xff0c;会自动生成如下所示文件#xff0c;可以根据…1. 动态库和导出和导入
1.1 动态库的导出
1. 创建新项目
新建新项目选择动态链接库DLL。 填写项目名称并选择项目保存的路径然后点击创建。 创建完成后会自动生成如下所示文件可以根据需要自行修改文件名。其中pch.h和pch.cpp一般是编写DLL函数的头文件和源文件。 同时编译器还会帮你在属性管理器中做三件事
将配置类型设置为动态库 在预处理中添加以你的工程名命名的动态库导出的宏定义以我的工程名myDLL为例会自动添加MYDLL.EXPORTS的宏定义这个宏定义后面会用到。 设置预编译头文件pch.h。这个就对应我们上面提到的pch.h和pch.cpp如果我们不想使用vs给我们提供的pch.h和pch.cpp可根据需要不使用预编译投或者修改预编译头文件的名字。 2. 编写DLL函数
1.编写pch.h文件
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能包括代码完成和许多代码浏览功能。
// 但是如果此处列出的文件中的任何一个在生成之间有更新它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件这将使得性能优势无效。#ifndef PCH_H
#define PCH_H// 添加要在此处预编译的标头
#include framework.h#ifdef MYDLL_EXPORTS#define DLLAPI __declspec(dllexport)
#else #define DLLAPI __declspec(dllimport)
#endifextern int DLLAPI g_value;class DLLAPI SimpleClass {
public:SimpleClass();~SimpleClass();int getValue() const;
};extern C
{DLLAPI int myAdd(int a, int b);DLLAPI int myMinus(int a, int b);DLLAPI int myMultipy(int a, int b);DLLAPI double myDevide(int a, int b);
}#endif //PCH_H
pch.h文件中定义了全局变量、类以及函数。其中MYDLL_EXPORTS 就是前面所述的宏定义在定义了MYDLL_EXPORTS后就会定义DLLAPI为__declspec(dllexport)。__declspec(dllexport)用于windows的动态库其作用是声明导出变量、函数、类、对象等供外面调用省略给出.def文件。
但是__declspec(dllexport)声明的函数会被转换为另一个名字这是因为C语言中有函数的重载而转换为另一个名字可以避免发生函数重载。当函数名被转换后我们在导入这个DLL库时就无法引用这个函数了。然而有一个方法可以避免这个事情的发生这就是extern C的作用它让编译器使用C方式的函数命名规则这样编译这个库后函数名就不会发生转换。对于类由于C语言中没有class所以无需对class加上extern C。
那有人有疑问了说为什么还要有一个#define DLLAPI __declspec(dllimport)呢其实这个定义加不加对于导出库是没有任何影响的但是对于导入库有影响。在MSDN文档里面进行了解释意思是如果不定义#define DLLAPI __declspec(dllimport)就不能独自使用全局变量g_value只能通过调用getValue()函数来返回g_value。也就是说如果DLL库中没有定义全局变量即使没有定义#define DLLAPI __declspec(dllimport)在导入该DLL库时编译也不会出现任何问题但是一旦定义了全局变量那导入该DLL库时就会有两种情况第一种情况是如果不独自使用该全局变量编译也不会出现任何问题通过调用getValue()函数也能返回正确的g_value第二种情况是独自使用该全局变量比如std::cout g_value std::endl;那么在编译时就会报错如下所示 综上所述一般在定义DLL的头文件时需要加上#define DLLAPI __declspec(dllimport)这句。
2.编写pch.cpp文件
// pch.cpp: 与预编译标头对应的源文件#include pch.h// 当使用预编译的头时需要使用此源文件编译才能成功。
int g_value 100;SimpleClass::SimpleClass()
{
}SimpleClass::~SimpleClass()
{
}int SimpleClass::getValue() const
{return g_value;
}int myAdd(int a, int b) {return a b;
}int myMinus(int a, int b) {return a - b;
}int myMultipy(int a, int b) {return a * b;
}double myDevide(int a, int b) {double m (double)a / b;return m;
}
3. 生成动态库
点击 生成-生成解决方案 即可注意这里解决平台是Debug x64后面调用的时候也必须和这个平台一致不然会报错。你也可以使用release只要做到前后一致即可。
生成的myDLL.dll和myDLL.lib保存在${projectName}/x64/Debug目录下如果你选择的其他release平台或者x86就保存在相应的目录下。 很多小伙伴会比较疑惑的一点是为什么我生成的DLL库但却会伴随着lib文件呢
其实lib文件有两个意思一个是静态库的意思但在这里是是导入库的意思。二者的使用方式相同含义完全不同。windows下的vs生成dll的时候会顺带生成lib导入库在导入DLL的时候可以显式导入即指定DLL的名字和DLL里面函数的名字这样比较麻烦或者使用导入库辅助这样就是为什么我们使用DLL的时候要在链接器指定lib导入库的原因了。
下面我们来看看如何导入动态库。
1.2 动态库的导入
1. 创建新项目
新建新项目选择空项目。 填写项目名称并选择项目保存的路径然后点击创建。 2. 属性配置和添加DLL库
1.配置属性
设置头文件目录 设置库目录 在链接器中添加导入库lib 2.添加DLL库到当前工作目录下 如果不添加DLL库就会出现找不到DLL文件的报错。
说白了上述的步骤是为了让项目可以找到库的头文件和库文件最简单粗暴的方法是把.h包含framework.h和pch.h、.dll和.lib文件都复制到当前的工作目录下。这样就无需进行前两项配置即无需配置头文件目录的属性和库目录的属性了。
3. 编写调用代码
新建源文件调用库的变量、函数和类。
#include pch.h
#include iostreamint main()
{//调用库函数int a 1;int b 2;int sum myAdd(a, b);std::cout sum std::endl; //3//调用库变量std::cout g_value std::endl; //100//调用库类SimpleClass cls;int val cls.getValue();std::cout val std::endl; //100
}
此时需要注意的是这里的导入DLL的项目中没有预定义MYDLL_EXPORTS所以pch.h中走的是#define DLLAPI __declspec(dllimport)这条支路这里编译就可以顺利通过了否则就会因为独自使用库中的全局变量而报错。 4. 生成可执行文件
点击三角符号进行生成并执行在终端即可看到执行结果。 此时在${projectName}/x64/Debug中即可看到exe文件。 2. 静态库和导出和导入
2.1 静态库的导出
1. 创建新项目 2. 编写LIB函数
1.编写pch.h文件
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能包括代码完成和许多代码浏览功能。
// 但是如果此处列出的文件中的任何一个在生成之间有更新它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件这将使得性能优势无效。#ifndef PCH_H
#define PCH_H// 添加要在此处预编译的标头
#include framework.hextern int g_value;class SimpleClass {
public:SimpleClass();~SimpleClass();int getValue() const;
};int myAdd(int a, int b);
int myMinus(int a, int b);
int myMultipy(int a, int b);
double myDevide(int a, int b);#endif //PCH_H
2.编写pch.cpp文件
// pch.cpp: 与预编译标头对应的源文件#include pch.h// 当使用预编译的头时需要使用此源文件编译才能成功。
int g_value 100;SimpleClass::SimpleClass()
{
}SimpleClass::~SimpleClass()
{
}int SimpleClass::getValue() const
{return g_value;
}int myAdd(int a, int b) {return a b;
}int myMinus(int a, int b) {return a - b;
}int myMultipy(int a, int b) {return a * b;
}double myDevide(int a, int b) {double m (double)a / b;return m;
}
3. 生成静态库
点击 生成-生成解决方案 即可注意这里解决平台是Debug x64后面调用的时候也必须和这个平台一致不然会报错。你也可以使用release只要做到前后一致即可。
生成的myDLL.lib保存在${projectName}/x64/Debug目录下如果你选择的其他release平台或者x86就保存在相应的目录下。 注意这里的myLIB.lib的文件明显比导出动态库中的.lib文件要大这也说明了.lib文件的两种含义。
2.2 静态库的导入
1. 创建新项目 2. 属性配置
设置头文件目录 设置库目录 在链接器中添加导入库lib 说白了上述的步骤是为了让项目可以找到库的头文件和库文件最简单粗暴的方法是把.h包含framework.h和pch.h和.lib文件都复制到当前的工作目录下。这样就无需进行前两项配置即无需配置头文件目录的属性和库目录的属性了。
3. 编写调用代码
#include pch.h
#include iostreamint main()
{//调用库函数int a 1;int b 2;int sum myAdd(a, b);std::cout sum std::endl; //3//调用库变量std::cout g_value std::endl; //100//调用库类SimpleClass cls;int val cls.getValue();std::cout val std::endl; //100
}4. 生成可执行文件
点击三角符号进行生成并执行在终端即可看到执行结果。此时在${projectName}/x64/Debug中即可看到exe文件。
3. 总结
DLL的导出步骤是
创建DLL项目编写DLL的.h文件和.cpp文件生成DLL
DLL的导入步骤是
创建空项目配置属性和添加DLL库到工程目录编写调用代码生成可执行文件
LIB的导出步骤是
创建LIB项目编写LIB的.h文件和.cpp文件生成LIB
LIB的导入步骤是
创建空项目配置属性编写调用代码生成可执行文件