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,一经查实,立即删除!

相关文章

为什么大多数TCP服务器采用多线程,以及如何从头开始构建一个多线程的TCP服务器

目录 前言 了解TCP服务器 设置TCP服务器 接受客户端的连接 读取并响应请求 实现一个循环以进行连续操作 Java举例 结论 前言 TCP是一种在计算机网络中用于机器之间通信的最可靠的方法在本文中&#xff0c;我们将探讨一个Web服务器如何处理和为多个TCP连接提供服务为了更…

Python exec() 函数初探

你好&#x1f596;&#xff0c;我是简讯&#xff01;一枚野生程序员。热爱编程&#xff0c;但目前的工作与编程毫无关系。 正在尝试各种副业&#xff0c;目前有做&#xff1a; 红包封面商城中视频计划 想要零成本一起参与红包封面商城的可以看这篇文章&#xff1a;副业实践&…

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

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

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

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

生信算法4 - 获取overlap序列索引和序列的算法

生信序列基本操作算法 建议在Jupyter实践&#xff0c;python版本3.9 1. 获取overlap序列索引和序列的算法实现 # min_length 最小overlap碱基数量3个 def getOverlapIndexAndSequence(a, b, min_length3):""" Return length of longest suffix of a matching…

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;启动…

PyQt5系列

基本使用 1、创建应用&#xff0c;初始化UI界面&#xff0c;创建布局盒子 # -*- coding: utf-8 -*- # Creator: zhu # Time: 2023-12-13 import xlwt import sys, base64, xlrd, re, datetime from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QApplication, QW…

windows下类Unix模拟环境,msys2,mingw,gcc的安装与环境配置

windows下常用的类Unix模拟环境&#xff1a; git fow windows&#xff1a;git等mingw&#xff1a;打包了gcc等编译器cygwin&#xff1a;大而全的类Unix环境支持msys2&#xff1a;自带大量预编译的软件包&#xff0c;提供pacman软件管理工具&#xff0c;能安装Unix下大部分软件…

039:我自己的 ostream_iterator

描述 程序填空输出指定结果 #include <iostream> #include <list> #include <string> using namespace std;template <class T1,class T2> void Copy(T1 s,T1 e, T2 x) {for(; s ! e; s,x)*x *s; }template<class T> class myostream_iteraot…

【星环云课堂大数据实验】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…

深入探索:Python 中 Scipy 的信号处理技术

写在开头 信号处理作为数字信号处理领域的关键技术&#xff0c;涵盖了从信号获取、传输、存储到最终应用的一系列处理步骤。在这篇博客中&#xff0c;我们将深入探讨Python中Scipy库在信号处理领域的应用。首先&#xff0c;我们会简要概述信号处理的基本概念&#xff0c;随后引…

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;我们…

GDB调试技巧实战--commands(断点回调)

commands的介绍 直接看gdb的help:commands会在关联的断点断住时被执行。 (gdb) help commands Set commands to be executed when a breakpoint is hit. Give breakpoint number as argument after "commands". With no argument, the targeted breakpoint is the …