小智 14
如果没有额外的上下文,我们并不完全清楚该引文所讨论的抽象级别。但如果是谈论操作系统的设计理念,可能是在谈论更底层。
您是否曾经问过自己,当您打电话时实际上会发生write()
什么?系统库可能会对这些值进行一些健全性检查,然后可能最终将它们交给操作系统内核。
这是你开始真正深入杂草的地方。它具体如何执行此操作将取决于您的操作系统,甚至它所运行的特定处理器架构。例如,Linux 内部使用syscall()
向内核发出系统调用信号。但你可能会再次问——syscall()
现在做什么?粗略地说,它以标准化形式将参数存储在某处,然后运行一条特殊的处理器指令,该指令切换到特权模式并跳转到操作系统内核中某处的系统调用处理程序。
现在没有什么可以阻止您删除所有这些中间人,只需将您的参数放入正确的处理器寄存器中,然后自己运行该指令即可。没有规则说你必须使用write()
, 甚至syscall()
. 这些功能只是为了方便起见,因为它们syscall()
可以在每个 Linux 上运行,无论处理器如何;并且write()
可以在任何机器上运行,无论操作系统如何。
我怀疑这可能就是你的书所谈论的内容,如果它谈论操作系统设计的话。作为开发人员,您不需要使用这些功能,但在绝大多数情况下您想要使用。然而,在幕后,这些函数本身必须由操作系统标准库的设计者来实现。它们本身就是 API——标准化接口,使您无需处理处理器内部结构。
Kaz*_*Kaz 11
调用系统调用的API是用代码编写的,例如C和内联汇编的混合。如果您愿意,可以将相同或类似的代码放入应用程序中。
\n这种做法很少见。该技术用于演示程序,用于展示没有库依赖项的完全独立的可执行文件可以有多小,但仍然可以做一些有用的事情。
\n开发非 C 编程语言运行时的人员可能会选择使用原始系统调用来避免对 C 库的依赖。
\n在 GNU/Linux 世界中,内核和用户空间几乎是完全独立的项目。可以想象这样一种情况,即已经开发了应用程序想要使用的一些有用的系统调用,但应用程序必须在 C 库较旧的系统中运行,并且不会将该系统调用公开为 API(但其内核是较新并且有系统调用)。在这种情况下,应用程序使用系统调用的唯一方法是自行发出它。
\n在某些情况下,API 并不直接对应于底层系统调用,并且出于性能等各种原因,应用程序开发人员决定将这些系统调用掌握在自己手中。
\n例如,在 GNU/Linux 上,用于在目录上打开类流对象并逐个读取目录条目的POSIX 函数opendir
和被实现为系统调用:用于将整批目录条目读入数组的函数。有人可能有兴趣直接使用这样的东西,而不是通过一对一的 API。readdir
getdents
注意事项的手册页getdents
:
SYNOPSIS\n int getdents(unsigned int fd, struct linux_dirent *dirp,\n unsigned int count);\n int getdents64(unsigned int fd, struct linux_dirent64 *dirp,\n unsigned int count);\n\n[...]\n\nNOTES\n Glibc does not provide a wrapper for these system calls; call them using\n syscall(2). You will need to define the linux_dirent or linux_dirent64 struc\xe2\x80\x90\n ture yourself. However, you probably want to use readdir(3) instead.\n
Run Code Online (Sandbox Code Playgroud)\n
通常,应用程序开发人员根据应用程序编程接口(API)来设计程序。
这意味着,作为程序员,我们不直接使用系统调用。
不,这意味着您通常不直接使用系统调用。您可以使用它们,但是在编程时您通常会使用一些更高级别的库并使用其 API 中的函数而不是系统调用。
例如,如果您正在编写 Gtk 应用程序,您将使用g_file_set_contents写入文件,而不是直接使用write,因为它更易于使用。
但是,如果您认为系统调用更适合您正在处理的任务,即使有更高级别可用,也没有什么可以阻止使用系统调用。
这通常取决于您正在开发的应用程序或库的类型。如果您正在编写新的低级库或系统工具,您可能会直接使用系统调用。如果您正在开发新的 GUI 应用程序,您可能会使用 Gtk 或 Qt 提供的 API。如果您使用某种更高级的编程语言,您可能会使用它的 API,例如Python 中的内置 open 。