基于VS2019的C++动态链接库DLL生成与调用

一、理论知识及实践经验

实验注意事项及部分程序编写规范(部分源自ChatGPT-3.5)

 __declspec(dllexport)和__declspec(dllimport)是用于在C++中定义动态链接库(DLL)的关键字。在编写动态链接库时,__declspec(dllexport)用于指示编译器将函数或变量导出到DLL中,以便其他程序可以使用它们(如此编译生成.dll时,导出关键字宏标记的函数或变量就会被标记为可供其它程序调用的符号)。而__declspec(dllimport)则用于告诉编译器在使用DLL中的函数或变量时,需要从DLL中导入它们(温馨提示:①“__”是两个下划线;②一些平台特定细节,导出的函数需要使用extern ”C“指定编译和链接规约);

 #pragma once是C++中的预处理器指令,用于确保头文件只被编译一次。当编译器遇到#pragma once指令时,它会检查该头文件是否已经被包含,如果是,则跳过该文件的处理,否则将其包含在编译过程中。这种方法与传统的使用#ifndef和#define宏来防止头文件被多次包含的方法相比,更加简洁和直观。使用#pragma once可以减少编译时间并避免由于多次包含同一头文件而引起的重定义错误

 #pragma comment(lib, "×××.lib") 是一个特殊的预处理器指令,用于告诉编译器在链接时将特定的库文件包含到可执行文件中。这个指令告诉编译器在链接时自动包含名为"×××.lib"的库文件,以简化编译过程,特别是对于需要链接静态库的情况。但是,该种方法是特定于编译器的,不是标准的C++语法,在不同的编译器中可能会有不同的行为。

整个程序中的预处理变量包括头文件保护符必须唯一,通常的做法是基于头文件中类的名字来构建保护符的名字,以确保其唯一性。为了避免与程序中的其它实体发生名字冲突,一般把预处理变量的名字全部大写[1];

在C++中,typedef关键字用于为现有的数据类型创建一个新的名称。这样做有助于提高代码的可读性和可维护性。例如,typedef int *ptr意味着指向int数据类型的指针别名为ptr;typedef int (*ptr)(int,int)意味着指向参数为两个int类型数据和返回值为int类型的函数的函数指针别名为ptr;

.dll生成配置环境需要与其调用环境相一致(如Debug/Release版本、×64/×86);

×××_EXPORTS(×××一般为大写项目名称)通常会在创建动态链接库DLL的项目中定义。在Visual Studio中,当你创建一个新的DLL项目时,通常会自动生成一个预定义的宏,名称类似于项目名称加上“_EXPORTS”。这样就可以根据这个宏的定义来选择是导出还是导入函数和变量;

命名域的使用可以有效避免部分不同文件同名函数冲突,格式为namespace{函数}。

编程拓展

        确保头文件多次包含仍能安全工作的常用技术是预处理器(preprocessor),它由C++语言从C语言继承而来。预处理器是在编译之前执行的一段程序,可以部分地改变我们所写的程序[1]。

       预处理器指令可以在编译前对源代码进行处理,用于控制编译过程和生成特定的代码结构,预处理器指令通常以#开头。 C++中的预处理器指令包括#include(用于包含其他文件的内容)、#define(用于定义宏/预处理变量)、#ifdef / #ifndef / #else / #endif(头文件保护符,用于条件编译)、#pragma(用于向编译器发出特定的命令)、#error(用于在预处理阶段生成一个错误消息)、#warning(用于在预处理阶段生成一个警告消息)、#undef(用于取消已定义的宏)以及#line(用于修改行号和文件名信息)。

        预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理变量,#ifdef(当且仅当变量已定义时为真) / #ifndef(当且仅当变量未定义时为真)两个指令分别检查某个指定的预处理变量是否已经定义。一旦检查结果为真,则执行后续操作直至遇到#endif指令为止[1]。常见组合代码行如下(注意,如果是多对#ifndef / #endif为就近配对):

                                        #ifndef ×××_H           (×××通常为编写类类名)

                                        #define ×××_H

                                        ....                             (此处可插入包含库文件、类的声明)

                                        #endif


        宏(Macro),在计算机编程中是指定如何将某个输入映射到替换输出的规则或模式。将宏应用于输入称为宏扩展。输入和输出可以是词汇标记或字符序列或语法树。软件应用程序支持字符宏,可以轻松调用常用命令序列。某些编程语言支持令牌和树宏,以实现代码重用或扩展语言,有时适用于特定领域的语言。宏用于使程序员可以将一系列计算指令作为单个程序语句使用,从而使编程任务不那么繁琐且不易出错。宏通常允许位置或关键字参数来指示条件汇编程序的内容和根据操作系统、平台或其他因素等变量生成并用于创建整个程序或程序套件[3]。

        在Windows模块开发中,宏经常和预处理指令#ifdef配合来控制模块的导出和导入符号;在跨平台开发时,通过宏和预处理指令配合,可以达到一定的代码开关控制,对不同的操作系统启用不同的代码;宏定义可以防止重复包含头文件;宏可以减少重复代码;宏可以简化部分信息输出[2]。  

二、实验实践

实验操作系统:Windows 10

实验高级程序设计语言:C++

实验开发环境:Visual Studio 2019

(一)C++源程序生成.dll动态链接文件及其使用[4][5][6][7]

1、编写生成.dll动态链接库

方法一

        方法一基于动态链接库(DLL)(项目模板)实现。需要注意的是,该模板自动提供预处理器定义CALCULATORAPIDLL_EXPORTS,而我们的项目名称为Calculator_API_DLL,实际上该处DLL导入导出宏需要匹配一致。

对应文件代码

// Calculator.h文件代码

// 预防重复包含头文件
#ifndef CALCULATOR_H
#define CALCULATOR_H


// Visual Studio创建DLL文件会自动添加Calculator_API_EXPORTS
// 通过宏与预处理命令控制DLL文件导入导出符号
#ifdef CALCULATORAPIDLL_EXPORTS
#define CalDLL_API __declspec(dllexport)
#else
#define CalDLL_API __declspec(dllimport)
#endif

// 包含标准库
#include<iostream>

// 添加结构体定义或函数定义
struct CalDLL_API CalNum
{
	int CalAdd(int, int);
	int CalSub(int, int);
	int CalPro(int, int);
	int CalDiv(int, int);
};

namespace CalculatorSpace
{
	void CalDLL_API printHello();
}


#endif //CALCULATOR_H




// Calculator.cpp文件代码

// 添加预编译头
#include "pch.h"

#include"Calculator.h"

using namespace std;

inline int CalNum::CalAdd(int a, int b)
{
	return a + b;
}

inline int CalNum::CalSub(int a, int b)
{
	return a - b;
}

inline int CalNum::CalPro(int a, int b)
{
	return a * b;
}

inline int CalNum::CalDiv(int a, int b)
{
	// 判断分母是否为除数
	if (b == 0)
	{
		cout << "分母不能为零!计算失败!" << endl;
		return 0;
	}
	else
		return a / b;
}

void CalculatorSpace::printHello()
{
	cout << "hello World!" << endl;
}

方法二

        方法二基于空项目(项目模板)实现。需要注意的是,该模板由于不提供预处理器定义,因此,我们可以i将DLL导入导出宏命名为”项目名称_EXPORTS“。

对应文件代码

// Calculator.h文件代码

// 预防重复包含头文件
#ifndef CALCULATOR_H
#define CALCULATOR_H


// 通过宏与预处理命令控制DLL文件导入导出符号
#ifdef Calculator_API_EXPORTS
#define CalDLL_API __declspec(dllexport)
#else
#define CalDLL_API __declspec(dllimport)
#endif

// 包含标准库
#include<iostream>

// 添加结构体定义或函数定义
struct CalDLL_API CalNum
{
	int CalAdd(int, int);
	int CalSub(int, int);
	int CalPro(int, int);
	int CalDiv(int, int);
};

namespace CalculatorSpace
{
	void CalDLL_API printHello();
}


#endif //CALCULATOR_H






// Calculator.cpp文件代码

#include"Calculator.h"

using namespace std;

inline int CalNum::CalAdd(int a, int b)
{
	return a + b;
}

inline int CalNum::CalSub(int a, int b)
{
	return a - b;
}

inline int CalNum::CalPro(int a, int b)
{
	return a * b;
}

inline int CalNum::CalDiv(int a, int b)
{
	// 判断分母是否为除数
	if (b == 0)
	{
		cout << "分母不能为零!计算失败!" << endl;
		return 0;
	}
	else
		return a / b;
}

void CalculatorSpace::printHello()
{
	cout << "hello World!" << endl;
}

2、主程序调用.dll动态链接库

实验代码

#include<iostream>
#include"Calculator.h"

using namespace std;

int main()
{
	int a, b;
	cout << "请输入需要进行计算的数字a与b:" << endl;
	cin >> a >> b;
	// 测试类的调用
	// 调用结构体默认构造函数
	CalNum Caculator;
	int A1 = Caculator.CalAdd(a, b);
	int A2 = Caculator.CalAdd(a, b);
	int A3 = Caculator.CalAdd(a, b);
	int A4 = Caculator.CalAdd(a, b);
	cout << "a+b=" << A1 << endl;
	cout << "a-b=" << A2 << endl;
	cout << "a*b=" << A3 << endl;
	cout << "a/b=" << A4 << endl;
	// 测试函数调用
	CalculatorSpace::printHello();
	return 0;
};

实验结果

参考资料:

[1] C++ Primer中文版:第5版 /(美)李普曼(Lippman,S.B.),(美)拉乔伊(Lajoie,J.),(美)默(Moo,B.E.)著;王刚,杨巨峰译. —北京:电子工业出版社,2013.9.

[2] C/C++宏的基本使用方法附例子讲解_c++宏machine-CSDN博客

[3] https://en.wikipedia.org/wiki/Macro_(computer_science)

[4] VS2019编译生成动态链接库dll的两种方式_vs 编译dll-CSDN博客

[5] 手把手教你如何制作和使用lib和dll_user_plc. lib怎么编写-CSDN博客

[6] VS2019-C++创建和调用DLL动态链接库(傻瓜式教程)_创建动态链接库-CSDN博客

[7] https://www.cnblogs.com/gongxijun/p/4368404.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/290341.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.babky勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

导言&#xff1a; 网络安全威胁不断进化&#xff0c;其中.babky勒索病毒引起了广泛关注。这篇文章91数据恢复将深入介绍.babky的狡猾特征&#xff0c;以及在遭受其袭击时如何高效地恢复被加密的数据&#xff0c;并提供实用的预防方法。当面对被勒索病毒攻击导致的数据文件加密…

mac环境下安装部署mysql5.7

下载安装包 进入官网下载MySQL5.7的安装包 https://www.mysql.com/downloads/ 安装包下载完成后双击pkg文件进行安装&#xff0c;无脑点下一步即可&#xff0c;注意安装完成后记得保存最后弹出框的密码 进入系统偏好设置&#xff0c;找到mysql&#xff0c;开启mysql服务…

详谈电商网站建设的四大流程!

在21世纪的互联网时代&#xff0c;电商网站的建设是每个企业发展不可缺少的一次机遇。企业商城网站建设成功也许会获得更大的了利润&#xff1b;如果网站建设不成功&#xff0c;那么也会带来一定的损失。所以建设电商网站不是那么一件简单的事情。那么电商网站制作流程是怎样的…

DoIP学习笔记系列:(八)车厂一般关于DoIP的相关测试分析

文章目录 1. 前言2. 基本项测试2.1 协议版本默认值2.2 车辆标识请求报文格式2.3 带EID的车辆标识请求报文格式2.4 带VIN的车辆标识请求报文格式2.5 否定响应码0x002.6 否定响应码0x012.7 否定响应码0x022.8 否定响应码0x042.9 路由激活应答码0x002.10 路由激活应答码0x012.11 路…

突发!博世「裁员」

对于未来几年的汽车行业需求变化&#xff0c;一级零部件供应商正在加快「降本增效」举措&#xff0c;犹如下游客户更加倾向于降本&#xff0c;而不是无休止的提升整车性能&#xff0c;比如&#xff0c;续航里程、智能化。 本周&#xff0c;全球汽车零部件龙头供应商博世宣布&am…

Linux学习第48天:Linux USB驱动试验:保持热情,保持节奏,持续学习是作为一个技术人员应有的基本素质和要求

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 最近更新的速度和频率大不如以前&#xff0c;主要原因还是自己有些懈怠了。学习是一个持续努力的过程&#xff0c;一旦中断&#xff0c;再想保持以往的状态可能要…

钡铼分布式IO在玻璃制造中的实时数据采集与监控应用介绍

导读 玻璃行业多年来一直广泛使用 PLC 来帮助管理生产过程所需的精确材料比例&#xff0c;完全依赖其PLC进行数据采集与控制&#xff0c;并且大量依靠人工来操作&#xff0c;所以这些高成本推动了对成本较低的替代方案的需求。 场景描述 某玻璃厂生产的玻璃生产包括配料段、熔…

性能测试之(六):JMeter 元件

元件&#xff08;多个类似功能组件的容器&#xff09; 组件&#xff1a;封装的方法&#xff0c;比如取样器中的发送请求的方法 一、常见的元件 1、取样器&#xff1a;发送请求2、逻辑处理&#xff1a;控制语句执行顺序3、前置处理器&#xff1a;在请求&#xff08;取样器&…

可狱可囚的爬虫系列课程 08:新闻数据爬取实战

前言 本篇文章中我带大家针对前面所学 Requests 和 BeautifulSoup4 进行一个实操检验。 相信大家平时或多或少都有看新闻的习惯&#xff0c;那么我们今天所要爬取的网站便是新闻类型的&#xff1a;中国新闻网&#xff0c;我们先来使用爬虫爬取一些具有明显规则或规律的信息&am…

陪诊系统|北京陪诊小程序提升陪诊服务效果

随着科技的不断发展&#xff0c;人们对于医疗服务的需求也越来越高。在过去&#xff0c;陪诊师和陪诊公司通常需要通过电话或传真等传统方式与医院进行沟通和安排。然而&#xff0c;现在有了陪诊小程序&#xff0c;这些问题得到了解决。本文将介绍陪诊小程序的开发流程和功能&a…

CSDN质量分批量查询

单个文章质量分查询地址&#xff08;点击右边地址&#xff09;&#xff1a; CSDN质量分查询 创作者身份认证审核标准 优质创作者申请条件&#xff1a; 粉丝数在5000以上近30日&#xff08;申请日算起&#xff09;原创文章数不少于4篇原创博文总数不少于100篇垂直领域原创数量…

CloudManager大数据本地环境标准部署文档

一、基本信息 文档目的&#xff1a;标准化、规范化Hadoop在本地化环境中部署所涉及的操作和流程&#xff0c;以便高效、高质地落地本地化环境部署的工作。 二、安装介质 FTP服务器&#xff1a; http://172.16.246.252:81/hadoopteam/cloudmanager/CDH-5.8.2-1.cdh5.8.2.p0.3…

swing快速入门(三十七)标签页

&#x1f308;注释很详细&#xff0c;直接上代码 上一篇 ⛱️新增内容 &#x1f525;1.设置标签页的位置与溢出内容布局方式 &#x1f525;2.设置标签图标与选中显示内容 &#x1f525;3.设置默认选中标签 &#x1f525;4.禁用标签 &#x1f525;5.获取选中标签的索引 &…

【文末送书】TVM编译器原理与实践

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

QT的坐标系统,回收机制、菜单栏,工具栏,状态栏,对话框及资源文件

QT的坐标系统&#xff0c;回收机制、菜单栏&#xff0c;工具栏&#xff0c;状态栏&#xff0c;对话框及资源文件 文章目录 QT的坐标系统&#xff0c;回收机制、菜单栏&#xff0c;工具栏&#xff0c;状态栏&#xff0c;对话框及资源文件1、QT的坐标系统&#xff1f;2、对象模型…

uni-app 从入门到精通 3天快速掌握 文字版 学习专栏

大家好&#xff0c;我是java1234小锋老师。 近日锋哥又卷了一波课程&#xff0c;uni-app 从入门到精通 3天快速掌握教程&#xff0c;文字版视频版。三天掌握。 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从…

百度Apollo:自动驾驶的领航者

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 粉丝福利活动 ✅参与方式&#xff1a;通过连接报名观看课程&#xff0c;即可免费获取精美周边 ⛳️活动链接&#xf…

获取CNN/DM适用于评估Bart的格式的数据集(类似于test.source、test.source.tokenized)

项目场景&#xff1a; 复现文本摘要任务评估CNN/DM数据集 问题描述 abisee老哥的代码获取的是bin格式的数据集 时间久远&#xff0c;一些依赖的配置版本难以复现 笔者需要能评估Bart 格式的数据集 形式类似于test.source、test.source.tokenized 解决方案&#xff1a; 经过坚…

婴儿专用洗衣机哪个牌子比较好?高性价比婴儿洗衣机推荐

随着家中新生命的降临&#xff0c;一大批婴儿专用的物品也陆续进入到家中&#xff0c;虽然有很多东西确实能在育儿之路上提供很多帮助&#xff0c;不过也有一些东西“很坑”。婴儿洗衣机这一产品是专为有婴幼儿的家庭或者有特殊需求的人士所研发的&#xff0c;它的容量以及体积…

死锁的处理策略“预防死锁”-第三十七天

目录 前言 破坏互斥条件 破坏不剥夺条件 破坏请求和保持条件 静态分配法 破坏循环等待条件 顺序资源分配法 本节思维导图 前言 死锁的产生必须满足四个必要条件&#xff0c;只要其中一个或几个条件不满足&#xff0c;死锁就不会发生 破坏互斥条件 互斥条件&#xff1a;…