Cherno C++学习笔记 P49 C++中使用静态库

这一篇文章当中我们来讲一下有关于C++当中的库以及怎么使用静态库。对于使用库这件事儿,C++确实是比其他语言更加棘手一些。如果我没用过python和其他语言,会发现直接import,库就进来了,非常的方便。但是对于C++,不同平台,不同configuration,都会导致我们的库没有办法使用,所以C++选手们通常都得被迫自己造轮子了。所以对于C++选手,在自己的解决方案当中保留自己所需要的所有的库非常重要,因为我们需要一下子就可以跑起来。尤其是当我们把项目传到比如GitHub上面的时候,有这种clone下来就能跑的特点也会方便我们的用户。

通常我们如果使用外部库,拿到的会是二进制形式的库文件。但是对于一些严肃项目来说,我们最好是能够拥有这些库的源代码,可以拿着代码先编译然后再作为库链接进来。这样的话更有助于我们调试。但是在这篇文章当中,我们还是拿二进制文件库举例子。

今天被我们拿来举例子的是GLFW库,这是一个专门针对OpenGL的C语言库,可以用来进行一些窗口的创建和操作工作。我们首先可以进入到GLFW官网下载:https://www.glfw.org/download.html

打开然后选择32/64位的适合Windows的预编译库,选择多少位的并不取决于我们目前计算机是多少位的,而是取决于我们要生成的那个目标应用要在多少位的平台上使用。在这里我们先下载一个32位的。然后解压缩看看里面有什么:

我们可以看到,里面有.dll和.lib两类文件。这也意味着库链接所包含的两种形式:静态链接static与动态链接dynamic。静态链接的时候,我们的静态库文件会直接嵌入到exe file当中去,这样我们也可以提前知道库里面包含的所有方法、变量、类等等。如果是动态链接,那么是在我们运行exe file的时候,再把它链接进去的。这需要我们在运行的时候把这个库放在某些合适的位置。我们的exe file对于动态库内部的具体内容通常不是很清楚的,需要用指针去寻找它们的位置。所以一般而言,静态链接会得到一些编译器内部优化的福利,这样会更快一些。这两者的本质区别,就是库里面的内容是否进入到了exe file当中去。

库通常包含两部分,分别是includes与library。include会包含一大堆头文件,而我们头文件里面的方法的定义就放在library当中了。通过包含头文件,我们的编译器就会知道现在我们有多少方法,然后我们在二进制文件当中去寻找这些方法的定义。

如何使用我们的GLFW库:首先我们随便新建一个解决方案,然后我们在解决方案文件夹目录下新建一个dependencies文件夹,然后在这个文件下新建一个GLFW文件夹。随后将我们include和最新的library文件夹都放在GLFW文件夹下面。接下来我们需要把include和library这两个文件路径都添加到我们的解决方案当中去。首先是include,我们在属性中找到additional include directory,然后把我们include文件夹添加进去。为了保证我们移动解决方案的位置,这里不会出错,所以可以使用宏SolutionDir来表示解决方案所在位置,然后添加上相对路径即可。

这样我们就把头文件添加进来了。然后我们可以include对应的头文件。这样就可以使用其中的函数且通过编译了。

cpp 复制代码
#include<iostream>
#include<glfw3.h>

int main() {
	int a = glfwInit();
	std::cin.get();
}

这里需要注意的一点是,在include的时候,这里无论是使用<>还是""都是可以的,因为我们的路径已经被添加到解决方案当中了。对于Cherno而言,他通常会选择,如果是自己写的库,有源代码的情况下,使用"";如果是外部解决方案,直接链接了二进制文件,那他通常会选择<>,反正这个只是一个风格问题,怎么用都随大家的便,有自己的习惯就可以了。

但是如果我们想要生成,是会发生错误的,因为我们其实没有告诉编译器我们的函数定义在哪里,那这就需要我们再把函数定义的内容包含进来了。我们需要在设置-链接器-常规-附加库目录当中,把我们的附加库添加进来,添加方式和之前是相同的。随后我们还要告诉编译器,具体我们添加的是哪个库,在这里面我们需要把我们用的库添加进去。

在这里我遇到的一个问题是,我必须要在添加的时候写上.lib才可以,否则的话它好像会选择打开.obj文件以至于找不到文件在哪里。然后我们让控制台打印一下我们输出的值,会发现输出的值是1,我们成功调用了已经写好的库当中的函数。

那么有一个问题,如果我们不include头文件,直接在自己的cpp文件中声明这个函数会发生什么?

cpp 复制代码
#include<iostream>

int glfwInit();

int main() {
	int a = glfwInit();
	std::cout << a << std::endl;
	std::cin.get();
}

这个时候会看到一个无法解析的外部符号报错,因为我们这个库其实是基于C的,所以我们直接这样写是不合法的,需要把声明函数的方式改成:

cpp 复制代码
extern "C" int glfwInit();

这样我们运行会发现结果和刚才是一样的。

以上就是有关于加载静态库的全部内容了,希望大家喜欢!

相关推荐
mykj155131 分钟前
英语单词APP解锁学习新方式,智能高效背单词
学习·英语单词app
知识分享小能手1 小时前
深度学习学习教程,从入门到精通,深度学习中的正则化 — 完整知识点与代码示例(7)
人工智能·深度学习·学习
~kiss~2 小时前
Agent 的 未来吗?String: An Agentic OS Where Every App Is a Markdown File
学习
Tairitsu_H2 小时前
[C++] 深入理解红黑树:封装set与map
开发语言·c++·set·map·红黑树·模拟实现
HugoStudio_SWAN3 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
猎头南楼4 小时前
VLA 模型落地端侧:从架构选型到量化部署的工程实践笔记
笔记·架构·大模型
会周易的程序员5 小时前
5Draft(五帝)测试报告
服务器·c++·分布式·raft·共识算法·共识·算力服务器
Capricorn19885 小时前
日志级幻觉排障:GPT-6 Astra 迈入 AGI 时代,知芽 Notebook Skill 如何以引用校验与零命中诚实弃权解决长文失忆
论文阅读·人工智能·笔记·gpt·agi
UIU1145 小时前
scanf与cout的误区:探究其内部的机制
c++·学习·c#·scanf
闻缺陷则喜何志丹5 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统