动态库与静态库

静态库 :链接时候被链接到可执行文件,文件体积较大

使用静态库需要有头文件和 *.lib文件

动态库:不被链接进入,动态加载,生成文件体积小

使用动态库需要有头文件 lib dll或者dll文件

库的用途:调用不同的库实现不同的功能,实现代码复用

静态库编写

加上extern "C"代表用C语言实现的函数

通常C语言写出来的库都比较通用

头文件xxx.h

1
2
3
4
#ifndef LIB_H
#define LIB_H
/*extern "C" */int add(int x,int y);
#endif

源文件xxx.c

1
2
3
4
5
6
#include "staticlib.h"

int add(int x,int y)
{
return x + y;
}

动态库编写

加上__stdcall后库中函数的名字会改变

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef _DLL_H_
#define _DLL_H_

#ifdef _EXPORT
#define DECLSPEC __declspec(dllexport) // 导出
#else
#define DECLSPEC __declspec(dllimport) // 导入
#endif

DECLSPEC int add(int x,int y);
DECLSPEC int __stdcall add2(int x,int y);
#endif // _DLL_H_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "dll.h"
#include <stdio.h>
#include <Windows.h>
int add(int x,int y)
{
return x + y;
}
int __stdcall add2(int x,int y)
{
return x + y;
}

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("process attach of dll\r\n");
break;
case DLL_THREAD_ATTACH:
printf("thread attach of dll\r\n");
break;
case DLL_THREAD_DETACH:
printf("thread detach of dll\r\n");
break;
case DLL_PROCESS_DETACH:
printf("process detach of dll\r\n");
break;
}

return TRUE;
}

调用静态库和动态库

调用静态库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <windows.h>
#include "..\staticlib\staticlib.h"

#pragma comment(lib, "..\\Debug\\staticlib.lib" )

int main()
{
// 静态库调用
int c = add(1,2);
printf("%d\r\n", c);

system("pause");
return 0;
}
1
2
//告诉编译器将staticlib.lib链接到本程序中
#pragma comment(lib, "..\\Debug\\staticlib.lib" )

或者可以在VS中添加

image-20231203232614373

调用动态库

第一种方法隐式调用需要有头文件,lib文件,dll文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <windows.h>
#include "..\dll\dll.h"
#pragma comment(lib, "..\\Debug\\dll.lib" )

typedef int (*lpAddFun)(int, int);
int main()
{

// 隐式调用
int c = add(1,2);
printf("%d\r\n", c);


system("pause");
return 0;
}

第二种方法只需要有dll文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <windows.h>
#include "..\dll\dll.h"
#pragma comment(lib, "..\\Debug\\dll.lib" )

typedef int (__stdcall *lpAddFun)(int, int);
typedef int (*lpAddFun2)(int, int);

int main()
{


// 显示调用DLL
HINSTANCE hDll; //DLL句柄
lpAddFun addFun; //函数指针
hDll = LoadLibrary("..\\Debug\\dll.dll");
if (hDll != NULL)
{
addFun = (lpAddFun)GetProcAddress(hDll, "_add@8");
//addFun = (lpAddFun)GetProcAddress(hDll, MAKEINTRESOURCE(1));
if (addFun != NULL)
{
int result = addFun(1, 2);
printf("%d\r\n", result);
}
FreeLibrary(hDll);
}

system("pause");
return 0;
}

如果在函数调用约定使用的是__stdcall ,函数名字就会发生改变

def文件可以告诉编译器那个函数要作为输出函数

1
2
3
LIBRARY dll文件名
EXPORTS // 代表导出
函数名 @ 序号

例如

1
2
3
4
5
LIBRARY my.dll
EXPORTS
add @ 1
push @ 3
sub @ 2