1. 了解 系统调用 与 C标准库

无论你用Java、Python、Go还是C++,当进行真正的I/O操作(网络读写、文件操作等)时,最终在底层都必须通过系统调用请求操作系统内核提供服务。高级语言的标准库或运行时只是对这些系统调用进行了封装。

用户态/内核态

可以把 系统调用想象成用户程序(比如你的Python脚本、Java程序)向操作系统"老大"请求服务的"标准接口"或"特许通道"

为了理解它,首先要明白操作系统的两个基本运行级别:

  • 用户态 我们编写的普通应用程序都运行在用户态。在这个级别,程序权限很低,不能直接访问硬件(如硬盘、网卡、摄像头)或执行某些特权指令。这是为了安全性和稳定性,防止一个程序崩溃或恶意程序影响到整个系统。
  • 内核态:操作系统内核运行在内核态。它拥有最高的权限,可以执行任何指令,直接操作所有硬件。

那么,当一个用户程序需要做它权限不够的事情时,比如读取一个文件、创建新进程、发送网络数据,该怎么办?

答案就是:系统调用系统调用用户程序 间接安全地 使用 计算机硬件 核心系统资源 唯一手段

系统调用 到底在哪儿

系统调用(具体代码)其实是操作系统内核的一部分(位于内核),通常用C和汇编编写。

操作系统内核中的系统调用的具体实现代码不会让上游程序直接去执行。也就是说你在编写 C 语言时不能直接调用内核中的直接地址去执行 系统调用的具体实现代码,而调用一个封装好的函数,这是操作系统内核对上游程序提供的 系统调用接口

系统调用的实现(代码逻辑) : 百分百属于内核。

系统调用的接口(函数名、参数规范): 是内核暴露给外界的使用方式。

这里有一个关键的层次关系:

你的应用程序 -> 标准库函数(如glibc中的open()) -> 系统调用接口 -> 内核中的系统调用实现

举个例子,当你调用 printf("Hello") 时:

  1. printf 是C标准库提供的函数。
  2. printf 函数内部会调用 write 这个系统调用接口
  3. 触发 write 后,CPU通过一个特殊的指令(如 syscall)从用户态 切换到内核态
  4. 此时,CPU开始执行操作系统内核中实现 write 功能的那段代码------这才是真正"属于内核"的系统调用。
  5. 内核代码执行完毕(将字符串送到标准输出),再切换回用户态,控制权交还给你的程序。

系统调用的过程可以分解为以下几步:

  1. 程序调用封装函数: 你的程序(比如C语言代码)调用一个标准的库函数,例如 read() 来读取文件。
  2. 触发软中断: 这个库函数内部会包含一段特殊的指令(例如 x86 架构上的 int 0x80syscall 指令)。执行这条指令会触发一个"软中断",导致CPU从用户态切换到内核态
  3. 内核接管: CPU跳转到内核中预设好的、专门处理系统调用的函数(系统调用处理程序)。
  4. 内核执行服务: 内核根据传入的系统调用编号(每个系统调用都有一个唯一编号,如 read 是某个数字)和参数(如文件描述符、缓冲区地址),在内核态安全地执行实际的硬件操作,比如从磁盘读取数据到内核的缓冲区。
  5. 返回结果: 操作完成后,内核将数据从内核缓冲区复制到用户程序提供的缓冲区,并将结果(成功或错误码)返回。
  6. 切换回用户态: CPU从内核态切换回用户态,程序继续执行,就好像刚从 read() 函数返回一样。

一般我们说系统调用,其实说的就是 系统调用接口,也就是一个个的系统调用函数。

系统调用

系统调用相当于是操作系统提供的一套用于和系统内核打交道的标准 ,无论是Linux、Windows还是macOS,它们都提供了一套固定的、有限的 系统调用集合。这个集合是操作系统内核的一部分。例如,在Linux中,系统调用有 readwriteopen 等。

它是操作系统内核提供的接口,用于用户程序请求内核服务, 但它并不是运行在用户态的库。

而且,操作系统通常会提供一个C库(如glibc、musl等)来封装系统调用 ,使得用户程序可以方便地使用C函数来调用系统调用。(因此,系统调用 是操作系统内核的功能,而 C库 是操作系统上带的一组库函数,它封装了系统调用)。

C 标准库

C标准库 是一个独立的、用户态 的共享库,由操作系统发行版提供 。也就是说,C标准库需要操作系统自带

它并不是 操作系统内核的一部分 : 内核运行在受保护的内核态,而 C标准库作为一个 .so (Linux) 或 .dll (Windows) 文件,和你的应用程序一样,运行在用户态。它没有特殊权限。

它属于"操作系统发行版" 当你安装Linux(如Ubuntu、CentOS)或Windows时,系统会自带一个特定版本的C标准库(如Linux上的glibcmusl)。它是操作系统提供给所有应用程序的一个最基础、最核心的运行库。

它的核心作用是封装系统调用,为所有应用程序(包括C程序、Python解释器、JVM等)提供一个统一、便捷、高级的接口来使用操作系统服务。

系统调用本身不是库,但C库是系统调用的常见封装。其他编程语言可能使用C库,也可能自己封装,但底层的系统调用是由操作系统制定的统一标准。

不同编程语言最终都会调用同一套系统调用(因为操作系统只提供这一套),但调用方式可能不同:通常通过C库封装,也可能直接通过汇编指令。

Linux 操作系统的系统调用 与 C标准库函数 的对应关系

Linux 操作系统的一些系统调用 与 C 标准库函数 例举:

可以看到C标准库中确实存在两组不同的I/O函数

  • 无缓冲I/O(Unbuffered I/O) :这一层的函数(如 read, write, open, close)是对系统调用的薄封装 ,函数名与系统调用基本一致。它们属于POSIX标准 ,在C标准库中通过 <unistd.h> 等头文件提供。
  • 标准I/O(Buffered I/O / Stream I/O) :这一层的函数(如 fread, fwrite, fopen, fclose)是高级的、带缓冲的封装 。它们属于ANSI C标准 ,在C标准库中通过 <stdio.h> 头文件提供。

小结

操作系统内核(提供系统调用) <--(封装)--> C标准库(如glibc)<--(调用)--> 各种编程语言(Python/Java/PHP等)的运行时/解释器

举个例子:你用Python写 open('file.txt')

  1. Python解释器(用C实现)接收到这个命令。
  2. 解释器内部会调用操作系统发行版上装的 C标准库的 fopen() 函数。
  3. fopen() 函数内部会调用操作系统底层的 open 系统调用(通过软中断进入内核)。
  4. 内核执行真正的打开文件操作。
  5. 结果一层层返回给Python程序。

系统调用本身是操作系统内核的功能。 它是内核代码的一部分,不是独立的库。你无法在用户空间直接"调用"它,必须通过特殊的硬件指令(软中断)进入内核。(ym:所以上面在介绍系统调用的过程时提到了, C 标准库函数内部会包含一段特殊的指令(例如 x86 架构上的 int 0x80syscall 指令)。执行这条指令会触发一个"软中断",导致CPU从用户态切换到内核态。)

C标准库(如glibc)是操作系统上的一个库。 它的一个重要职责就是封装系统调用,为用户程序提供一个更友好、更安全、更高级的C语言函数接口。


相关推荐
用户68545375977693 小时前
🔍 CPU不高但响应慢:性能排查的福尔摩斯式推理!
后端
用户904706683573 小时前
java hutool 工具库
后端
鄃鳕3 小时前
Flask【python】
后端·python·flask
渣哥3 小时前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
桦说编程3 小时前
CompletableFuture API 过于复杂?选取7个最常用的方法,解决95%的问题
java·后端·函数式编程
冲鸭ONE3 小时前
新手搭建Spring Boot项目
spring boot·后端·程序员
Moonbit3 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
世界哪有真情4 小时前
Trae 蓝屏问题
前端·后端·trae
Moment4 小时前
NestJS 在 2025 年:对于后端开发者仍然值得吗 😕😕😕
前端·后端·github