Visual Studio 2022封装C代码为x64和x86平台动态库

1.引言

本文介绍如何使用Visual Studio 2022C语言函数封装成x64x86平台上使用的动态链接库(dll文件)并生成对应的静态链接库(lib文件),以及如何在C++程序中调用生成的dll。

程序下载:

2.示例C语言程序

假设需要开发一个动态链接库,实现复数的四则运算,定义如下头文件ComplexCal.h和源码文件ComplexCal.c。

(1)ComplexCal.h

#ifndef COMPLEXCAL_H
#define COMPLEXCAL_H
//定义复数结构体
typedef struct {double real;double imag;
} Complex;
//复数加法
Complex add(Complex a, Complex b);
//复数减法
Complex subtract(Complex a, Complex b);
//复数乘法
Complex multiply(Complex a, Complex b);
//复数除法
Complex divide(Complex a, Complex b);
#endif //COMPLEXCAL_H

(2)  ComplexCal.c

#include "CompplexCal.h"
/*** 复数加法* @param a Complex结构体* @param b Complex结构体* @return Complex结构体*/
Complex add(Complex a, Complex b) {Complex result;result.real = a.real + b.real;result.imag = a.imag + b.imag;return result;
}
/*** 复数减法* @param a  Complex结构体* @param b  Complex结构体* @return  Complex结构体*/
Complex subtract(Complex a, Complex b) {Complex result;result.real = a.real - b.real;result.imag = a.imag - b.imag;return result;
}
/*** 复数乘法* @param a  Complex结构体* @param b  Complex结构体* @return  Complex结构体*/
Complex multiply(Complex a, Complex b) {Complex result;result.real = (a.real * b.real) - (a.imag * b.imag);result.imag = (a.real * b.imag) + (a.imag * b.real);return result;
}/*** 复数除法* @param a Complex结构体* @param b Complex结构体* @return Complex结构体*/
Complex divide(Complex a, Complex b) {Complex result;double denominator = b.real * b.real + b.imag * b.imag;result.real = (a.real * b.real + a.imag * b.imag) / denominator;result.imag = (a.imag * b.real - a.real * b.imag) / denominator;return result;
}

3.创建Visual Studio 动态链接库工程并定义宏指令

3.1 创建dll工程

接下来说明如何创建Visual Studio动态链接库工程并编写相应的dll封装头文件。新建complex_cal文件夹,然后打开Visual Studio,在该目录下创建dll工程,如动图所示,然后将将示例头文件和源码文件复制到complex_cal/ComplexCal文件夹(Visual Studio解决方案文件ComplexCal.sln文件所在文件夹)内。

Visual Studio会预先创建 framework.hpch.hpch.cdllmain.cpp等4个模板文件,其中pch.h为预编译标头文件,这里用不上这些模板文件,可以将其移除或者删除。

  3.2 添加示例头文件和源码文件到解决方案内

首先需要添加ComplexCal.h(添加到头文件下)ComplexCal.c(添加到源文件下)文件到Visual Studio解决方案资源管理器内,才能让Visual Studio加载。

3.3 取消使用预编译标头

另外还需取消使用预编译标头,否则将出现C1010错误:

 取消方法在项目属性/C/C++/预编译头选项下选择不使用预编译头,如下所示:

注意在头部配置和平台上选中所有配置所有平台

3.4 在头文件中添加dll宏指令

ComplexCal.h中添加以下宏,导出函数给外部调用:

#ifndef COMPLEXCAL_H
#define COMPLEXCAL_H
//定义复数结构体
typedef struct {double real;double imag;
} Complex;//dll入口宏指令
#ifndef  COMPLEXCAL_H_API_EXPORTS
#define  COMPLEXCAL_H_API_EXPORTS __declspec(dllexport)
#endif // !COMPLEXCAL_H_API_EXPORTS//根据不同平台定义函数调用堆栈修饰宏
#ifdef _WIN64 || _M_X64//x64平台#define dll_std_call __stdcall
#elif _WIN32 || _M_IX86// x86平台
#define dll_std_call __cdecl
#endif// 一般用于将C++代码以标准C形式输出(即以C的形式被调用)
// 告诉编译器下面大括号括起来的函数是c语言函数(因为c++和c语言对函数的编译转换不一样,主要是c++中存在重载)
#ifdef __cplusplus        
extern"C" {                 
#endif
//复数加法__declspec(dllexport) Complex dll_std_call  add(Complex a, Complex b);
//复数减法__declspec(dllexport) Complex dll_std_call subtract(Complex a, Complex b);
//复数乘法__declspec(dllexport) Complex dll_std_call multiply(Complex a, Complex b);
//复数除法__declspec(dllexport) Complex dll_std_call divide(Complex a, Complex b);
#ifdef __cplusplus
}
#endif
#endif //COMPLEXCAL_H

3.5  选择目标平台并生成解决方案来生成dll

在Visual Studio工具栏上选择dll的构建配置和目标平台,例如Debug和x64。在Visual Studio中,Debug和Release是两种不同的构建配置。它们之间的主要区别在于编译器如何优化代码并生成可执行文件。

在Debug模式下,编译器会生成包含调试符号的二进制文件。这些符号可以用于在代码中设置断点、跟踪变量值等操作,以便进行调试。此外,编译器通常会关闭优化,以便使得调试更容易。

在Release模式下,编译器通常会启用各种优化,以生成更快、更紧凑的代码。这些优化可能会包括删除未使用的代码、内联函数、循环展开和其他技术。此外,由于没有调试符号,生成的文件大小也比Debug模式下的要小得多。

 然后运行工具栏生成/生成解决方案来生成dll。

对于x64平台,生成的dll文件位于解决方案(.sln文件)同目录的x64文件夹下,对于Debug构建配置,位于x64/DebugRelease构建配置位于x64/Release。对于x86平台的Debug构建配置,则位于解决方案文件同目录的Debug文件夹,x86平台的Release构建配置则位于解决方案文件同目录的Release文件夹。

 打开上述目录,其中的ComplexCal.dllComplexCal.lib即我们需要的dll文件,其它文件为编译和链接所需的中间文件。

4.在C++程序中引用动态库

4.1 演示工程配置

创建C++控制台应用,测试生成的复数运算dll。首先使用Visual Studio创建一个控制台应用工程,命名为ComplexCalApplication

将上述生成的dlllib文件以及ComplexCal.h头文件复制到解决方案文件ComplexCalApplication.sln所在目录的include文件夹下,这里以X64_Release为例。

然后添加ComplexCal.h头文件到解决方案资源管理器的头文件下,让Visual Studio能发现该文件。还需在项目属性->C/C++->常规选项下添加include文件夹为附加包含夹,以让链接器能发现并链接dlllib文件:

另外定义生成后事件,让Visual Studio自动复制dll文件到可执行文件所在目录,避免出现dll丢失错误。生成后事件指令如下:

xcopy /y "$(ProjectDir)\include\*.dll" "$(TargetDir)"

上述命令表示在生成结束后自动将 include文件夹下的dll文件复制到可执行文件所在目录内。在项目属性中定义生成后事件的方法如下:

4.2 dll调用

在C++程序中调用dll以下几个步骤:

  1. 将 DLL 的头文件包含到应用程序中。
  2. 定义生成后事件将dll文件复制到可执行文件所在文件夹下。

如代码所示:

#include <iostream>
//引入dll头文件
#include "include/ComplexCal.h"
int main()
{Complex a, b, sum, difference;std::cout << "Enter the real and imaginary parts of the first complex number: ";std::cin >> a.real >> a.imag;std::cout << "Enter the real and imaginary parts of the second complex number: ";std::cin >> b.real >> b.imag;sum = add(a, b);difference = subtract(a, b);std::cout << "Sum: " << sum.real << " + " << sum.imag << "i" << std::endl;std::cout << "Difference: " << difference.real << " + " << difference.imag << "i" << std::endl;return 0;}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

for-each循环优先于传统的for循环

在大多数情况下&#xff0c;使用 for-each 循环&#xff08;也称为增强型 for 循环&#xff09;比传统的 for 循环更加简洁和方便。它提供了一种更直观的方式来遍历集合或数组中的元素。以下是一个例子&#xff0c;展示了 for-each 循环优于传统 for 循环的情况&#xff1a; i…

AI智能配音助手微信小程序前后端源码支持多种声音场景选择

大家好今天给大家带来一款配音小程序 &#xff0c;这款小程序支持多种不同声音和场景的选择更人性化&#xff0c; 比如说支持各地区的方言,英文,童声呀等等、 另外也支持男声女声的选择,反正就是模板那些非常的多 当然啦音量,语调,语速那些都是可以DIY跳转的哟,所以说这一款小程…

python每日学11:xpath的使用与调试

背景&#xff1a;最近在使用selenium 模拟浏览器作一些常规操作&#xff0c;在使用selenium的过程中接触到的一种定位方法&#xff0c;叫xpath, 这里说一下使用心得。 首先&#xff0c;我觉得如果只是简单使用的话是不用详细了解具体的语法规则的。 一、xpath怎么用&#xff1…

树莓派(Raspberry Pi)4B密码忘记了,怎么办?

树莓派长时间不用&#xff0c;导致密码忘记了&#xff0c;这可咋整&#xff1f; 第1步&#xff1a;取出SD卡 将树莓派关机&#xff0c;移除sd卡&#xff0c;使用读卡器&#xff0c;插入到你的电脑。 第2步&#xff1a;编辑 cmdline.txt 在PC上打开SD卡根目录&#xff0c;启动…

【星环云课堂大数据实验】kafka消息发布与订阅

文章目录 一、Kafka概述二、实验环境三、实验准备四、实验目的五、实验步骤5.1、创建Kafka Topic5.2、Kafka消息发布5.3、Kafka消息订阅 六、实验感悟 一、Kafka概述 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。该项目的目标是为处理实…

内存的管理、扩充、存储保护、地址转换、分配和回收

一、 内存的存储保护 1.1 上、下限寄存器方式&#xff1a; 上、下限寄存器&#xff08;Limit Registers&#xff09;&#xff1a;这是一种硬件级别的内存保护机制。每个进程都有一对上、下限寄存器&#xff0c;用于定义该进程能够访问的内存范围。上限寄存器存储进程能够访问的…

【Android12】WindowManagerService架构分析

Android WindowManagerService架构分析 WindowManagerService(以下简称WMS) 是Android的核心服务。WMS管理所有应用程序窗口(Window)的Create、Display、Update、Destory。 因为Android系统中只有一个WMS&#xff08;运行在SystemServer进程&#xff09;&#xff0c;可以称其为…

快宝技术:连接无代码开发,API集成提升电商营销和用户运营效率

无代码开发&#xff1a;创新的启航 快宝技术自2012年成立至今&#xff0c;一直是无代码开发领域的佼佼者。通过无代码开发平台&#xff0c;快宝技术旨在降低技术门槛&#xff0c;并使非技术人员能够轻松创建和部署应用程序。这不仅使得快递末端软件开发变得高效和便捷&#xf…

vue3.0项目搭建

一、安装vue3脚手架 卸载vue2脚手架 npm uninstall -g vue-cli清除缓存 npm cache clen --force安装最新脚手架 npm install -g vue/cli查看脚手架版本 vue -V 二、构建项目 创建项目 vue create 项目名选择配置 自定义配置&#xff0c;回车 上下键选择Linter / Formatter&a…

DC-2靶场

DC-2 下载地址&#xff1a;DC and Five86 Series Challenges - Downloads​编辑https://www.five86.com/downloads.html DC-2环境配置&#xff1a;解压后在vm虚拟机点击左上方文件-->打开-->选择解压后的DC-2。把kali和DC-2的网路适配器都改成NAT模式 flag1 首先进行主…

【教程】从零开始的ORB-SLAM3的安装与配置

引言 最近项目需求需要接触vslam&#xff0c;博主选择从ORB-SLAM3下手并且记录下安装的基本流程。不得不说&#xff0c;这安装流程就像二大娘的裹脚布。 大致环境前提&#xff1a;Ubuntu20.04 一、ORB-SLAM3的源码下载 1、首先&#xff0c;为了方便管理文件&#xff0c;我们…

面向对象三大特征之二:继承

继承的快速入门 什么是继承&#xff1f; Java中提供了一个关键字extends&#xff0c;用这个关键字&#xff0c;可以让一个类与另一个类建立起父子关系 继承的特点 子类能继承父类的非私有成员&#xff08;成员变量、成员方法&#xff09; 继承后对象的创建 子类的对象是由…

MyBatis Plus 大数据量查询优化

大数据量操作的场景大致如下&#xff1a; 数据迁移 数据导出 批量处理数据 在实际工作中当指定查询数据过大时&#xff0c;我们一般使用分页查询的方式一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据或分很大一页查询数据时&#xff0c;如果一下子将数…

RTX 40 SUPER发布时间定了!价格也有了

快科技12月16日消息&#xff0c;NVIDIA RTX 40 SUPER系列显卡基本确定将在2024年1月8日正式发布&#xff0c;也就是CES 2024大展期间&#xff0c;随后在1月中下旬陆续解禁上市。 RTX 4070 SUPER 1月16日解禁公版/原价丐版&#xff0c;1月17日解禁高价高配版&#xff0c;上市开…

测试架构师必备技能-Nginx安装部署实战

Nginx(“engine x”)是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的免费开源Web和 反向代理服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。在高并发访问的情况下&#xff0c;Nginx是Apache服务器不错的替代品。官网数据显示每秒TPS高达50W左右。本文为读者朋…

FPGA设计时序约束十二、Set_Clock_Sense

目录 一、序言 二、Set Clock Sense 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 命令示例 三、工程示例 3.1 工程代码 3.2 无set_clock_sense 3.3 设置set_clock_sense 四、参考资料 一、序言 本章将介绍Set_Clock_Sense约束&#xff0c;在介绍约束之前&#xff0…

《Kotlin核心编程》笔记:反射、注解和加锁

Kotlin 和 Java 反射 1&#xff09;Kotlin 的 KClass 和 Java 的 Class 可以看作同一个含义的类型&#xff0c;并且可以通过.java和.kotlin方法在KClass和Class之间互相转化。2&#xff09;Kotlin 的 KCallable 和 Java 的 AccessiableObject 都可以理解为可调用元素。Java 中构…

Redis List类型

列表类型是用来存储多个有序的字符串&#xff0c;如图所示&#xff0c;a、b、c、d、e 五个元素从左到右组成了一个有序的列表&#xff0c;列表中的每个字符串称为元素 (element)&#xff0c;一个列表最多可以存储2的32次方 -1个元素。在 Redis 中&#xff0c;可以对列表两端插入…

Linux 基本语句_15_Tcp并发服务器

原理&#xff1a; 利用父子进程。父进程接收客户端的连接请求&#xff0c;子进程处理客户端的数据处理操作&#xff0c;两者各施其职。最终实现能够多个客户端连接一个服务端的操作。 代码&#xff1a; 服务端代码&#xff1a; #include <stdio.h> #include <sys/…