C语言学习篇(28)——函数库

引言

我们在编写代码时,常常会写一个.c源文件和与之对应的.h文件(例如a.c和a.h),并在源文件.c中定义(具体实现)一些函数,在.h文件中声明, 这样我们就可以在其他源文件中包含该头文件,来调用之前写的函数,这样做的好处就是避免了重复劳动,同时也可以调用一些大神的代码。 但是有时候我们不想公开自己的源代码(.c),尤其是商业性代码,同时又要让客户能够使用他们编写的代码,解决的方法就是打包成静态链接库(.a,.lib)或动态链接库(.so, .dll),同时提供对应的头文件.h, 譬如我们经常使用的stdio.h , string.h等C库函数,这些统称为函数库, 那么我们今天就来聊聊什么是函数库,函数库有什么作用,如何制作函数库等等话题。

什么是函数库

函数库就是一些事先写好的函数集合。 因为函数是模块化的,不同的功能封装成一个个不同的函数,可以是被反复调用,当A写好了一个功能函数,然后共享出来,此时B 有同样的需求就不用自己重写实现该功能了,直接调用A写的函数即可,避免了重复劳动。 而且由于共享免费的原因,这些函数会经过很多人测试使用,并不断优化,其可靠性是非常之高的,最终形成标准,譬如glibc。

函数库的提供形式

目前函数库主要的提供2种形式:动态链接库和静态链接库。

比较早出现的是 静态链接库,其实质是商业公司或个人将自己的函数库源代码经过只编译不链接,形成各个.o目标文件,然后用ar(gcc中 binutils 工具集,主要用来创建和管理连接程序使用的目标库文档)工具将各个.o(windows下.obj)文件归档成.a(或.lib),即静态链接库文件,然后通过发布.a库文件和.h头文件来提供静态库给他人使用,而其他人则通过.h头文件得知库中的库函数原型,然后在自己的.c文件中直接调用这些函数,并且在编译链接时,链接器(ld)会去.a文件中拿出被调用的哪个函数编译后的.o二进制代码段链接形成最终的可执行程序。这就是静态链接库的原理。

动态链接库比静态链接库出现的晚一些,那么动态链接库和静态链接库有什么区别呢? 静态库是指链接器从静态链接库获取所有被引用函数,并将这些函数加入到可执行文件中。这样做的好处是代码装载速度快,但是缺点很明显可执行文件体积较大,包含相同的公共代码,造成浪费。而动态链接库呢,避免了重复加载相同的代码块,因此更节省空间,但是其本身程序是不完整的,在整体运行速度比静态库慢。 我们通过一个简单的hello world例子来感受下:

<code>#include 

int main(void)
{
	printf("hello world.\n");
	
	return 0;
}/<code>

我们调用glic库中stdio中的printf函数,打印hello world, 然后我们编译运行(这里我们不加任何参数选项,即默认使用动态链接的方式),并通过ls -l命令查看编译生成的可执行文件a.out的文件大小:8.4K

C语言学习篇(28)——函数库

接着我们在通过参数选项(-static),指定使用静态链接方式再次编译,看看此时可执行文件a.out的文件大小:891K

C语言学习篇(28)——函数库

两者方式都成功运行了“hello world”,但使用静态链接方式得到的可执行文件远远大于使用动态链接库方式。

静态链接方式中,在有多个应用程序都使用了这个库函数时,结果会在多个应用程序最后生成的可执行程序中都各自有一份这个库函数的代码段。当这些应用程序同时在内存中运行时,实际上在内存中有多个这个库函数的代码段,这完全重复浪费了。而动态链接库本身不将库函数的代码段链接入可执行程序,只是做个标记。然后当应用程序在内存中执行时,运行时环境发现它调用了一个动态库中的库函数时,会去加载这个动态库到内存中,然后以后不管有多少个应用程序去调用这个库中的函数都会跳转到第一次加载的地方去执行(不会重复加载)。

C语言学习篇(28)——函数库

总结

今天我们主要分析了函数库的概念,以及2种表现方式:动态链接库和静态链接库,并介绍了两者的区别,以及如何使用静态库来编译我们的代码。之后我会讲解如何不同平台下(gcc, keil armcc下)制作我们自己静态和动态链接库,方便大家将自己的代码共享给别人,同时也能保护自己的知识产权。好了,今天的分享到此,喜欢的话欢迎关注,转发加收藏哦~


C语言学习篇(28)——函数库



分享到:


相關文章: