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

news2024/11/23 16:14:27

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.coloradmin.cn/o/1315950.html

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

相关文章

Linux(操作系统)面经——part 1(持续更新中......)

1、说一说常用的 Linux 命令 mkdir创建文件夹&#xff0c;touch创建文件&#xff0c;mv移动文件内容或改名 rm-r 文件名&#xff1a;删除文件 cp拷贝&#xff1a;cp 文件1 文件2&#xff0c;cp-r跨目录拷贝 cp-r 路径1 路径2 vi 插入 &#xff1a;wqb保存退出 :q!强制退出…

W25N01GV 芯片应用

项目中处于成本考虑&#xff0c;要把Nor Flash换成低成本的Nand Flash。 这里总结下芯片应用。 总体概述&#xff1a; 1&#xff09;W25N01&#xff08;NandFlash&#xff09;和W25Q&#xff08;Nor Flash&#xff09;的操作大不一样。 NandFlash擦除以块&#xff08;128KB&…

计算BMI指数-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第19讲。 计算BMI指数&…

【TB作品】基于单片机的机械通风控制系统,实时温度和二氧化碳浓度

硬件&#xff1a; &#xff08;1&#xff09;51系列单片机&#xff0c;拟采用STC89C52RC&#xff1b; &#xff08;2&#xff09;DS18B20温度传感器&#xff1b; &#xff08;3&#xff09;二氧化碳浓度传感器&#xff1a;https://item.taobao.com/item.htm?spma21n57.1.0.0.1…

DS八大排序之冒泡排序和快速排序

前言 前两期我们已经对"插入排序"&#xff08;直接插入排序和希尔排序&#xff09; 和 "选择排序"&#xff08;直接选择排序和堆排序&#xff09;进行了详细的介绍~&#xff01;这一期我们再来详细介绍一组排序 &#xff1a;"交换排序"即耳熟能…

lv12 uboot移植深化 9

u-boot-2013.01移植 【实验目的】 了解u-boot 的代码结构及移植的基本方法 【实验环境】 ubuntu 14.04发行版FS4412实验平台交叉编译工具arm-none-linux-gnueabi- 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行 【实验步骤】 1 建立自己的平台 1.…

在线客服系统定价因素解析:影响价格的关键因素

跨境电子商务公司必不可少的工具就是在线客服系统。企业选择在线客服系统的时候免不了要对不同产品的功能性、价格、服务等因素进行考量。今天这篇文章&#xff0c;我们就来探讨一下在线客服系统的定价因素有哪些&#xff1f;探究市面上的在线客服系统价格各异的影响因素。为大…

libp2p 快速开始

文章目录 第一部分&#xff1a;libp2p 快速入门一、什么是libp2plibp2p 发展历程libp2p的特性p2p 网络和我们熟悉的 client/server 网络的区别&#xff1a; 二、Libp2p的实现目标三、Libp2p的用途四、运行 Libp2p 协议流程libp2p 分为三层libp2p 还有一个局域网节点发现协议 mD…

27系列DGUS智能屏发布:可实时播放高清模拟信号摄像头视频

针对高清晰度的模拟信号摄像头视频画面的显示需求&#xff0c;迪文特推出27系列DGUS智能屏。该系列智能屏可适配常见的AHD摄像头、CVBS摄像头&#xff0c;支持单路1080P高清显示、两路720P同屏显示&#xff08;同一类型摄像头&#xff09;。用户通过DGUS简单开发即可实现摄像头…

netty-daxin-3(rpc远程调用)

文章目录 nettyRpcObjectEncoder 与 ObjectDecoderjdk动态代理回顾Rpc调用过程简析服务端客户端 nettyRpc ObjectEncoder 与 ObjectDecoder ObjectEncoder继承自MessageToByteEncoder<Serializable>&#xff0c;它内部使用ByteBufOutputStream包装ByteBuf对象&#xff…

SpringBoot 自动装配原理---源码详解

目录 SpringBoot 自动装配原理源码流程详解&#xff1a;流程总结&#xff1a;条件匹配解释&#xff1a;其他解释&#xff1a; SpringBoot 自动装配原理 源码流程详解&#xff1a; 1、先看启动类&#xff0c;启动这个main方法&#xff0c;然后调用这个run方法。 2、把 启动类作…

一文了解Tomcat

文章目录 1、Tomcat介绍2、Tomcat使用配置2.1、Tomcat下载启动2.2、Tomcat启动乱码2.3、Tomcat端口号修改 3、Tomcat项目部署4、IDEA中使用Tomcat方式 1、Tomcat介绍 什么是Tomcat ​ Tomcat是Apache软件基金会一个核心项目&#xff0c;是一个开源免费的轻量级web服务器&#x…

Networkx实现小世界网络的分析

Networkx实现小世界网络的分析 小世界网络 小世界现象&#xff0c;也被称为六度分离原则&#xff0c;即如果你在地球上的任何地方随便选择任何两个人&#xff0c;你会发现一条至多由他们之间的6个熟人形成的路径。在网络科学语言中&#xff0c;六度也被称为小世界性质&#x…

C++相关闲碎记录(16)

1、正则表达式 &#xff08;1&#xff09;regex的匹配和查找接口 #include <regex> #include <iostream> using namespace std;void out (bool b) {cout << ( b ? "found" : "not found") << endl; }int main() {// find XML/H…

【C++干货铺】继承后的多态 | 抽象类

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 多态的概念 多态的定义和实现 多态的定义条件 虚函数 虚函数的重写 特殊情况 协变&#xff08;基类和派生类的虚函数返回值不同&#xff09; 析构函数的重…

如果你找不到东西,请先确保你在正确的地方寻找

之前我们在几篇文章中描述了如何进行”思想”调试&#xff0c;今天的文章我将不会这样做。 因为下面的编程错误大部分人都会遇到&#xff0c;如果你看一眼下面的代码&#xff0c;你不会发现有什么问题&#xff0c;这仅仅是因为你的的大脑只给你希望看到的&#xff0c;而不是那…

分数约分-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第20讲。 分数约分&#xf…

算法模板之单链表图文讲解

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;算法模板、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️使用数组模拟单链表讲解1.1 &#x1f514;为什么我们要使用数组去模拟单链表…

appium2.0.1安装完整教程+uiautomator2安装教程

第一步&#xff1a;根据官网命令安装appium&#xff08;Install Appium - Appium Documentation&#xff09; 注意npm前提是设置淘宝镜像&#xff1a; npm config set registry https://registry.npmmirror.com/ 会魔法的除外。。。 npm i --locationglobal appium或者 npm…

多线程 (上) - 学习笔记

前置知识 什么是线程和进程? 进程: 是程序的一次执行,一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间&#xff0c;一个进程可以有多个线程&#xff0c;比如在Windows系统中&#xff0c;一个运行的xx.exe就是一个进程。 线程: 进程中的一个执行流&#xff0…