一、Windows下的静态库
其实静态库在Windows平台上还是好创建和使用的,由于VS这个IDE的存在,创建一个静态库是非常简单的了,在VS2019中和前面的版本略有不同,打开VS2019后,点击“创建新项目”,在右侧的窗口中有三个选项,最左侧为语言,选择“C++”,当中选择“Windows”,最后一个选择“库”,在下面选择需要的“静态库”。点击“下一步”,会出现“项目名称”,“位置”,“解决方案”几个设置选项,根据个人喜好创建即可。最后点击“创建”即可成功。
运行这个空的程序即可生成一个默认的静态库。
通过学习知道,静态库是最初的二进制代码共享方式,在一些核心的算法场景上,为了安全,有时还是会用静态库。静态库的优劣在前面已经讲过多次了,其实用静态库就是为了偷懒,应用方可以减少对各种库的依赖以及复杂的配置环境。这里为了把Windows的库的开发进行一个总结,这里使用一个比较复杂的方式,即两个静态库互相调用,然后用一个动态库调用这两个静态库,最后用一个EXE工程来调用它们。
二、例程
看一个基础的例程:
//lib staticlib1.h
#pragma once
void fnStaticLib1();
//lib staticlib1.cpp
#include "pch.h"
#include "framework.h"
#include <iostream>
// TODO: 这是一个库函数示例
void fnStaticLib1()
{
std::cout << "this is static lib!" << std::endl;
}
//exe
#include <iostream>
#include "../StaticLib1/StaticLib1.h"
int main()
{
fnStaticLib1();
std::cout << "Hello World!\n";
}
库编译成功,但是EXE程序编译报错,链接错误,找不到fnStaticLib1,这里打开工程的“属性”-“链接器”-“常规”-“附加库目录”,写入库的位置路径,再在“链接器”-“输入”-“附加依赖项”写入库的名字,注意用分号隔开,再次编译成功。运行,就会出现两次打印的数据
三、动静态库的互调
在前面提到过,静态库和动态库的互相调用是比较复杂的,这里给出一个基本的框架,在这个小的框架中,其实有很多小坑的,比如前面提到的头文件的少包含等,都会导致低级错误引起的不易查找的BUG。
第一个静态库:
//firstlib.h
#pragma once
void fnfirstlib();
//firstlib.cpp
#include <stdlib.h>
#include <stdio.h>
#include "firstlib.h"
extern "C"
{
#include "..\..\seclib\seclib\seclib.h "
}
#pragma comment(lib,"seclib.lib")
// TODO: 这是一个库函数示例
void fnfirstlib()
{
fnseclib();
printf("call first static lib ! ");
}
第二个静态库:
//seclib.h
#pragma once
void fnseclib();
//seclib.cpp
#include <stdlib.h>
#include <stdio.h>
#include "seclib.h"
// TODO: 这是一个库函数示例
typedef struct __AB
{
int a;
int b;
}AB;
void fnseclib()
{
AB * tmp = (AB*)malloc(8);
tmp->a = 100;
tmp->b = 1;
printf("cur value is:%d,%d\n",tmp->a,tmp->b);
free(tmp);
}
第三个动态库:
//jumplib.h
#pragma once
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllimport)
#else
#define MYDLL_API __declspec(dllexport)
#endif
MYDLL_API int Sum(int a, int b);
MYDLL_API int Mul(int c, int d);
//jumplib.cpp
#include "jumplib.h"
//extern "C"
//{
#include "../../firstlib/firstlib/firstlib.h"
//}
#pragma comment(lib,"firstlib.lib")
int Sum(int a, int b)
{
fnfirstlib();
return a + b;
}
int Mul(int c, int d)
{
return c * d;
}
第四个工程:
//TestDllLib.cpp
#include <iostream>
//#define MYDLL_EXPORTS
#include "../../testDll/testDll/jumplib.h"
#pragma comment(lib,"testDll.lib")
int main()
{
int d = Sum(1,1);
std::cout << "Hello World!\n";
}
依次编译,然后再把编译好的库拷贝到执行路径和工程路径下,在最后的可执行工程中运行即可看到效果。这里没有采用上面的路径设置方法,而是使用"pragma comment"这个宏来引用库的位置,更加灵活一些。
四、注意点
静态库的使用范围肯定是越来越小,但还是要注意一些:
1、库的使用尽量单一,引用尽量单向。
2、静态库尽量符合设计功能最小功能原则。
3、如果库需要一个单实例模式的实现,请使用动态库。
4、同样,要注意X64平台和X32平台的问题。
五、总结
Windows平台上的静态库开发相比LINUX上的静态库开发,要复杂不少,但是静态库的调试和控制还是比动态库要好进行一些,毕竟在一个库里跳来跳去,比到处找动态库要有优势,掌握了基础的开发方式,再加不断的工程实践,那么在Windows平台上的开发就不会有什么大问题了。
努力要从今日始,苟日新,日日新。