C/C++编写静态链接库、动态链接库和使用def导出(VS2019)

静态链接库

1.使用VS2019创建静态链接库

在这里插入图片描述

2.创建完成后结构如下

在这里插入图片描述

3.在pch.h添加声明

// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"



int Plus(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
int Div(int x, int y);

#endif //PCH_H

4.在StaticTestLib.cpp里面添加实现代码

// StaticTestLib.cpp : 定义静态库的函数。
//

#include "pch.h"
#include "framework.h"



int Plus(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}


在这里插入图片描述

5.新建需要添加lib的工程调用lib

在这里插入图片描述

// 源.cpp : 
#include <iostream>
#include "pch.h"
#pragma comment (lib,"StaticTestLib.lib")
int main()
{
	printf("%d", Plus(2, 1));
}

5.运行结果

在这里插入图片描述

静态链接库的缺点:

1.使用静态链接生成的可执行文件体积较大,造成浪费
2.我们常用的printf、memcpy、strcpy等就来自这种静态库
3.并不是真正意义上的模块化

动态链接库

1.使用VS2019创建动态链接库

在这里插入图片描述

2.创建完成后结构如下

在这里插入图片描述

3.新建一个类用来装你需要的函数

//TestDll.h
#pragma once
#include "pch.h"

#ifdef IMPORT_DLL
#else
#define IMPORTSTD_DLL extern "C" _declspec(dllexport)
#endif 


IMPORTSTD_DLL int _stdcall Plus(int x, int y);
IMPORTSTD_DLL int _stdcall Sub(int x, int y);
IMPORTSTD_DLL int _stdcall Mul(int x, int y);
IMPORTSTD_DLL int _stdcall Div(int x, int y);
//这里楼主写了两种隐式链接没加_stdcall ,显示连接加了_stdcall 
//TestDll.cpp
#include "pch.h"
#include "TestDll.h"


int _stdcall Plus(int x, int y)
{
	return x + y;
}
int _stdcall Sub(int x, int y)
{
	return x - y;
}
int _stdcall Mul(int x, int y)
{
	return x * y;
}
int _stdcall Div(int x, int y)
{
	return x / y;
}


在这里插入图片描述

说明:
1、extern 表示这是个全局函数,可以供各个其他的函数调用;
2、“C” 按照C语言的方式进行编译、链接
__declspec(dllexport)告诉编译器此函数为导出函数;
_stdcall 内平栈;

4.使用Dll

方式一:隐式连接

步骤1:将 *.dll *.lib 放到工程目录下面
步骤2:将 #pragma comment(lib,“DLL名.lib”) 添加到调用文件中
步骤3:加入函数的声明
extern “C” __declspec(dllimport) __stdcall int Plus (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Sub (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Mul (int x,int y);
extern “C” __declspec(dllimport) __stdcall int Div (int x,int y);

说明:
__declspec(dllimport)告诉编译器此函数为导入函数;

#include <iostream>
#pragma comment(lib,"TestDll.lib")

extern "C" __declspec(dllimport)  int Plus(int x, int y);
extern "C" __declspec(dllimport)  int Sub(int x, int y);
extern "C" __declspec(dllimport)  int Mul(int x, int y);
extern "C" __declspec(dllimport)  int Div(int x, int y);

int main()
{
	printf("%d", Plus(2, 1));

}

在这里插入图片描述

方式二:显式连接

步骤1: //定义函数指针

typedef int(_stdcall* lpPlus)(int, int);
typedef int(_stdcall* lpSub)(int, int);
typedef int(_stdcall* lpMul)(int, int);
typedef int(_stdcall* lpDiv)(int, int);

步骤2: //声明函数指针变量

lpPlus myPlus;					 	
lpSub mySub;					 	
lpMul myMul;					 	
lpDiv myDiv;

步骤3: // //动态加载dll到内存中

HINSTANCE hModule = LoadLibrary("TestDll.dll");
if (!hModule)
{
	printf("%s","加载动态库失败!");
	getchar();
}

步骤4: //获取函数地址

myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");

步骤5: //调用函数

int a = myPlus(10,2);					
int b = mySub(10,2);					
int c = myMul(10,2);					
int d = myDiv(10,2);			

特别说明:

Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。						
HMODULE 是代表应用程序载入的模块	
HINSTANCE 在win32下与HMODULE是相同的东西 Win16 遗留			
HWND 是窗口句柄	
其实就是一个无符号整型,Windows之所以这样设计有2个目的:						
						
1、可读性更好										
2、避免在无意中进行运算											
完整调用Cpp:
#include <iostream>
#include <Windows.h>
#pragma comment(lib,"TestDll.lib")

typedef int(_stdcall* lpPlus)(int, int);
typedef int(_stdcall* lpSub)(int, int);
typedef int(_stdcall* lpMul)(int, int);
typedef int(_stdcall* lpDiv)(int, int);

	
int main()
{
	lpPlus myPlus;
	lpSub mySub;
	lpMul myMul;
	lpDiv myDiv;

	HINSTANCE hModule = LoadLibrary("TestDll.dll");
	if (!hModule)
	{
		printf("%s","加载动态库失败!");
		getchar();
	}
	myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
	mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
	myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
	myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");
	int a = myPlus(10, 2);
	int b = mySub(10, 2);
	int c = myMul(10, 2);
	int d = myDiv(10, 2);
	printf("%d", myPlus(2, 1));
	getchar();
	return 0;
}

在这里插入图片描述

使用Def导出

1.添加def文件

在这里插入图片描述

2.添加代码

LIBRARY
EXPORTS	
	
Plus   	@12
Sub		@15 NONAME
Mul    	@13
Div    	@16

3.编译查看结果

sub函数已经被隐藏了
在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态是一种可重定位的二进制文件,它包含了一些可供其他程序调用的函数或数据。在 Windows 平台上,动态采用 .dll 后缀名,而在 Linux 平台上则采用 .so 后缀名。在本文中,我们将介绍如何使用 MFC 调用 C 语言编写动态。 # 创建动态 在 Windows 平台上,可以使用 Visual Studio 创建动态。下面是一个简单的示例: ```c // mydll.h #ifndef MYDLL_H #define MYDLL_H #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) int add(int a, int b); #ifdef __cplusplus } #endif #endif // MYDLL_H // mydll.c #include "mydll.h" int add(int a, int b) { return a + b; } ``` 这个动态包含一个 add 函数,可以对两个整数求和。 # 调用动态 在 MFC 项目中调用动态,需要进行以下几个步骤: 1. 定义一个函数指针类型,指向动态中的函数。 ```c++ typedef int (*AddFunc)(int, int); ``` 2. 加载动态。 ```c++ HINSTANCE hinstLib = LoadLibrary(TEXT("mydll.dll")); if (hinstLib == NULL) { AfxMessageBox(TEXT("Failed to load library.")); return; } ``` 3. 获取动态中的函数地址。 ```c++ AddFunc addFunc = (AddFunc)GetProcAddress(hinstLib, "add"); if (addFunc == NULL) { AfxMessageBox(TEXT("Failed to get function address.")); FreeLibrary(hinstLib); return; } ``` 4. 调用动态中的函数。 ```c++ int result = addFunc(1, 2); CString str; str.Format(TEXT("1 + 2 = %d"), result); AfxMessageBox(str); ``` 5. 卸载动态。 ```c++ FreeLibrary(hinstLib); ``` 完整的 MFC 代码示例: ```c++ typedef int (*AddFunc)(int, int); void CMyDlg::OnButton1() { HINSTANCE hinstLib = LoadLibrary(TEXT("mydll.dll")); if (hinstLib == NULL) { AfxMessageBox(TEXT("Failed to load library.")); return; } AddFunc addFunc = (AddFunc)GetProcAddress(hinstLib, "add"); if (addFunc == NULL) { AfxMessageBox(TEXT("Failed to get function address.")); FreeLibrary(hinstLib); return; } int result = addFunc(1, 2); CString str; str.Format(TEXT("1 + 2 = %d"), result); AfxMessageBox(str); FreeLibrary(hinstLib); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值