什么是 Linux 系统调用和库函数?
开发计算机软件是为了使某些任务自动化或解决某些问题。无论哪种方式,软件都借助该软件的开发人员编写的逻辑来实现目标。每个逻辑都需要一些服务,例如计算字符串的长度、打开文件等。标准服务由一些仅为此目的提供的函数或调用提供。
和计算字符串长度一样,有strlen()这样的标准函数,打开文件有open()和fopen()这样的函数。我们将这些函数称为标准函数,因为任何应用程序都可以使用它们。
这些标准功能可分为两大类:
- 库函数调用。
- 系统函数调用。
在本文中,我们将尝试以各种点的形式讨论系统和库调用背后的概念,并且在需要时,将提供两者之间的区别。
1. 库函数与系统调用
作为标准 C 库一部分的函数称为库函数。例如,strcmp()、strlen() 等标准字符串操作函数都是库函数。
将程序的执行模式从用户模式更改为内核模式的函数称为系统调用。如果程序需要内核中的某些服务,则需要这些调用。例如,如果我们想更改系统的日期和时间,或者如果我们想创建一个网络套接字,那么这些服务只能由内核提供,因此这些情况需要系统调用。例如,socket() 是一个系统调用。
2. 为什么需要系统调用?
系统调用充当操作系统内核的入口点。只有当进程在内核模式下运行时才能完成某些任务。这些任务的示例可以是与硬件等交互。因此,如果一个进程想要执行此类任务,那么它将要求自己在内核模式下运行,这可以通过系统调用实现。
3.库函数的类型
库函数可以有两种类型:
- 不调用任何系统调用的函数。
- 进行系统调用的函数。
有些库函数不进行任何系统调用。例如,strlen() 等字符串操作函数就属于这一类。此外,还有一些库函数可以进一步进行系统调用,例如 fopen() 函数,它是标准库函数,但在内部使用 open() 系统调用。
4.组件之间的交互
下图描述了库函数、系统调用、应用程序代码如何相互交互。
上图清楚地表明应用程序代码可以与库函数或系统调用进行交互。此外,库函数也可以从内部调用系统函数。但是只有系统调用才能访问内核,内核可以进一步访问计算机硬件。
5. fopen() 与 open()
我们中的一些人可能会争辩说,为什么我们有两个函数用于同一个操作,即打开一个文件?
嗯,这个问题的答案是 fopen() 是一个库函数,它提供用于打开文件的缓冲 I/O 服务,而 open() 是一个提供非缓冲 I/O 服务的系统调用。虽然 open() 函数也可供应用程序使用,但应用程序应避免直接使用它。
一般来说,如果存在对应于系统调用的库函数,则应用程序应该使用该库函数,因为:
- 库函数是可移植的,这意味着使用标准库函数的应用程序将在所有系统上运行。另一方面,依赖于相应系统调用的应用程序可能不会在每个系统上运行,因为系统调用接口可能因系统而异。
- 有时,相应的库函数会减少系统调用的负载,从而导致从用户模式到内核模式的不频繁切换。例如,如果有一个应用程序非常频繁地从文件中读取数据,那么使用 fread() 而不是 read() 将提供缓冲 I/O,这意味着并非每次调用 fread() 都会导致调用系统调用 read ()。fread() 可以一次性读取更大的数据块(比用户需要的数据),因此后续的 fread() 将不需要调用系统函数 read()。
6. malloc() 是系统调用吗?
这是人们非常普遍的误解之一。让我们明确一下 malloc() 不是系统调用。函数调用 malloc() 是一个库函数调用,它进一步使用 brk() 或 sbrk() 系统调用进行内存分配。
7.系统调用:切换执行模式
传统上,使用向内核引发“int $0x80”中断的机制。捕获中断后,内核对其进行处理并将执行模式从用户模式更改为内核模式。今天,systenter/sysexit 指令用于切换执行模式。
8. 其他一些差异
除了上述所有内容之外,还有一些系统调用和库调用之间的区别:
- 库函数链接到用户程序并在用户空间执行,而系统调用不链接到用户程序并在内核空间执行。
- 库函数执行时间计入用户级时间,而系统调用执行时间计入系统时间的一部分。
- 库函数可以使用调试器轻松调试,而系统调用无法调试,因为它们是由内核执行的。
- 点赞
- 收藏
- 关注作者
评论(0)