代码复用

代码复用

在C中,代码复用主要有三种实现方式:

  • 静态链接库
  • 动态链接库
  • 使用.def 导出

静态链接库

特点

  • 利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中;我们常用的printf、memcpy、strcpy等就来自这种静态库
  • 一旦静态库发生了变化,程序如果要用则就要重新编译

使用方法

创建静态链接库
1、在VC6中创建项目:Win32 Static Library
2、在项目中创建两个文件:xxx.h 和 xxx.cpp

xxx.h文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#if !defined(AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_)	
#define AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


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

xxx.cpp文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}

3、编译
使用静态链接库:
方式一:

将xxx.h 和 xxx.lib复制到要使用的项目中

在需要使用的文件中包含:#include “xxx.h”

在需要使用的文件中包含:#pragma comment(lib, “xxx.lib”)

方式二:

将xxx.h 和 xxx.lib复制到要使用的项目中

在需要使用的文件中包含:#include “xxx.h”

动态链接库

创建DLL

1、源文件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
2、头文件中:
1
2
3
4
extern "C" _declspec(dllexport) __stdcall int Plus(int x, int y);
extern "C" _declspec(dllexport) __stdcall int Sub(int x, int y);
extern "C" _declspec(dllexport) __stdcall int Mul(int x, int y);
extern "C" _declspec(dllexport) __stdcall int Div(int x, int y);
说明:

1、extern 表示这是个全局函数,可以供各个其他的函数调用;

2、”C” 按照C语言的方式进行编译、链接

__declspec(dllexport)告诉编译器此函数为导出函数;

使用DLL

方式一:隐式连接

步骤1:将 * .dll * .lib 放到工程目录下面

步骤2:将 #pragma comment(lib, “DLL名.lib”) 添加到调用文件中

步骤3:加入函数的声明

1
2
3
4
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)告诉编译器此函数为导入函数;

方式二:显示链接

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

1
2
3
4
5

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: //声明函数指针变量

1
2
3
4
lpPlus myPlus;
lpSub mySub;
lpMul myMul;
lpDiv myDiv;

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

1
HINSTANCE   hModule = LoadLibrary("DllDemo.dll");

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

1
2
3
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: //调用函数

1
2
3
4
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、避免在无意中进行运算

*.def文件

EXPORTS

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

好处

名字是一段程序就精华的注释,通过名字可以直接猜测到函数的功能。

通过使用序号,可以达到隐藏的目的。