C语言链接库
静态链接库
静态链接库编译之后有两种使用方法。
将.h和.lib文件复制到项目根目录,然后在代码中引用
1
2将xxxx.h与xxxx.lib文件复制到VS安装目录,与库文件放在一起,然后在项目->设置->Linker->input下的Additional Dependencies添加lib文件名,之后就像使用std一样直接引用头文件就行了。
静态链接库的缺点
使用静态链接库生成的可执行文件体积较大,编译器将代码直接编译到模块里了
包含相同的公共代码,造成浪费
动态链接库
入口函数
1 | extern "C" BOOL WINAPI DllMain ( |
如下,在头文件中声明要导出的函数
1 |
|
extern “C”的意义是指示编译器这部分代码按照C语言进行编译而不是C++
另一种导出方式是使用.def文件,那么声明函数时就不需要extern关键字
1 | LIBRARY "xxxx" |
使用序号导出的好处:可以隐藏函数名
使用动态链接库
运行时动态链接
通过函数指针的方法调用dll,则不需要使用头文件
将dll文件移动到项目目录,或者在项目属性>调试>环境选项中配置PATH=dll路径;$PATH$
,这个路径是dll文件所在的路径,如果在Debug文件夹下那就要包含Debug文件夹。一般开发时不需要这么做,直接把dll文件放到项目目录就行了
定义函数指针
1
2typedef int (__stdcall *lpAdd)(int,int);
typedef int (__stdcall *lpSub)(int,int);声明函数指针变量
1
2lpAdd myAdd;
lpSub mySub;动态加载dll到内存中
1
HINSTANCE hModule = LoadLibrary("A.dll");
获取函数地址
1
2
3
4
5myAdd = (lpAdd)GetProcAddress(hModule,"add");
myAdd = (lpAdd)GetProcAddress(hModule,"sub");
/*通过序号获取函数地址*/
add = (fcAdd)GetProcAddress(hMod, (LPCTSTR)12);调用函数
释放动态链接库
1
FreeLibrary(hModule);
示例
1 |
|
注意在DLL项目中要将.def文件添加进模块编译目录,否则.def文件是不会被编译,而且.def文件开头使用LIBRARY指定模块名称
在Project->Property pages->Linker->input->Module Definition File下指定.def文件,比如说A.def,要写全。
用pe工具查看输出表,没有名字的就是sub函数
加载时动态链接
加载时动态链接可以像静态库一样调用dll,将头文件、.lib
文件和dll放入项目目录。
或者将头文件路径加入包含目录,将.lib
文件路径加入到库目录中,然后就可以直接调用dll的函数
1 |
|
隐式链接
隐式链接的lib文件里只储存了描述性的信息,如果没有lib文件的话只能通过GetProcAddress显式获取函数地址。
将编译后的lib文件和dll一起复制到项目根目录
将
#pragma comment(lib,"xxx.lib")
添加到调用文件中加入函数声明
1
2__declspec(dllimport) int __stdcall add(int a, int b);
__declspec(dllimport) int __stdcall sub(int a, int b);
隐式链接时编译器会在exe文件里生成一张输出表,详细记录了用到哪些dll,和dll里的哪些函数。
在pe工具中查看输出表: