LV055-库函数
一、库函数
系统调用是内核直接向应用层提供的应用编程接口, 譬如 open、 write、read、 close 等,关于这些系统调用后面学习。 编写应用程序除了使用系统调用之外,我们还可以使用库函数。
库函数也就是 C 语言库函数, C 语言库是应用层使用的一套函数库, 在 Linux 下,通常以动态(.so)库文件的形式提供,存放在根文件系统/lib 目录下, C 语言库函数构建于系统调用之上,也就是说库函数其实是由系统调用封装而来的,当然也不能完全这么说, 原因在于有些库函数并不调用任何系统调用,例如一些字符串处理函数 strlen()、 strcat()、 memcpy()、 memset()、 strchr()等等; 而有些库函数则会使用系统调用来帮它完成实际的操作,如库函数 fopen 内部调用了系统调用 open()来帮它打开文件、库函数 fread()就利用了系统调用 read()来完成读文件操作、 fwrite()就利用了系统调用 write()来完成写文件操作。
Linux 系统内核提供了一系列的系统调用供应用层使用, 我们直接使用系统调用就可以了呀,那为何还要设计出库函数呢?事实上, 有些系统调用使用起来并不是很方便, 于是就出现了 C 语言库,这些 C 语言库函数的设计是为了提供比底层系统调用更为方便、更为好用、 且更具有可移植性的调用接口。
库函数与系统调用
- 库函数是属于应用层,而系统调用是内核提供给应用层的编程接口,属于系统内核的一部分;
- 库函数运行在用户空间,调用系统调用会由用户空间(用户态)陷入到内核空间(内核态);
- 库函数通常是有缓存的,而系统调用是无缓存的,所以在性能、效率上,库函数通常要优于系统调用;
- 可移植性:库函数相比于系统调用具有更好的可移植性,通常对于不同的操作系统,其内核向应用层提供的系统调用往往都是不同,譬如系统调用的定义、功能、参数列表、返回值等往往都是不一样的;而对于 C 语言库函数来说,由于很多操作系统都实现了 C 语言库, C 语言库在不同的操作系统之间其接口定义几乎是一样的,所以库函数在不同操作系统之间相比于系统调用具有更好的可移植性。
从实现者的角度来看,系统调用与库函数之间有根本的区别,但从用户使用角度来看,其区别并不重要,它们都是 C 语言函数。 在实际应用编程中,库函数和系统调用都会使用到,所以对于我们来说,直接把它们当做是 C 函数即可,知道自己调用的函数是系统调用还是库函数即可,不用太过于区分它们之间的差别。所以应用编程简单点来说就是:开发 Linux 应用程序,通过调用内核提供的系统调用或使用 C 库函数来开发具有相应功能的应用程序。
二、标准 C 语言库函数
1. GNU C 库
在 Linux 系统下,使用的 C 语言库为 GNU C 语言函数库(也叫作 glibc ,其网址为 The GNU C Library - GNU Project - Free Software Foundation),作为 Linux 下的标准 C 语言函数库。 我们点开官网,就可以看到下载的地方。
2. glibc 版本?
我们怎么确定 Linux 系统的 glibc 版本 ?前面提到过了, C 语言库是以动态库文件的形式提供的,通常存放在/lib 目录,它的命名方式通常是 libc.so.6,不过这个是一个软链接文件,它会链接到真正的库文件。
进入到 Ubuntu 系统的/lib 目录下,我使用的 Ubuntu 版本为 20.04,在我的/lib 目录下并没有发现 libc.so.6 这个文件, 其实是在/lib/x86_64-linux-gnu 目录下,进入到该目录:

可以看到 libc.so.6 链接到了 libc-2.23.so 库文件, 2.31 表示的就是这个 glibc 库的版本号为 2.31。除此之外,我们还可以直接运行该共享库来获取到它的信息,如下所示:

从打印信息可以看到, 我当前所使用的 Ubuntu 系统对应的 glibc 版本号为 2.31。