⚙️ 第九章 操作系统与应用程序的关系
📄 一句话概括

系统调用=请求操作系统办事的方式;高级语言把它包成一套写法,于是同一份代码在多个系统上都能跑——这就是可移植性。

📝 本节和前面几节的关系

9.2 说清了操作系统的存在,这一节讲【差异是怎么被压住的】。

一、系统调用是什么

程序要操作系统办事,不能直接闯进去,得走规定的入口。 这个入口就叫系统调用——打开文件、读写、申请内存、创建进程,都从这儿走。 走规定的入口有三个好处:系统能检查你该不该做、能记账(谁用了多少资源)、能保护别人不被你影响。 所以系统调用既是【通道】,也是【关口】。

二、包一层,就有了可移植性

麻烦在于:每个操作系统的系统调用都不一样(7.3 讲过)。 高级语言的做法是再包一层:向上提供一套统一的写法,向下分别调用各家的系统调用。 于是同一份代码在多个系统上都能跑——这就叫可移植性。 注意可移植性的真正含义:不是代码没变,而是【要变的那部分不用你写。

三、实测看这套封装

os.sep 是当前系统的路径分隔符,os.linesep 是行尾换行。 实测:Windows 上是反斜杠与回车加换行两个字符。 换成别的系统,这两个值都会变——但调用它们的代码一行都不用改。 这就是抽象化的实际效果:差异被压在语言运行时那一层里了。

四、可移植性也不是白来的

统一接口只能取各家功能的交集。 某一家的独门功能,不好用上。 多层封装有开销。 一层层转发是实打实的成本。 【可移植】不等于【行为一致】。 同一个写法在两个系统上可能有细节差别——所以真正的跨平台程序都得在每个系统上真跑一遍。 记住这句话就够了:可移植性降低了你的工作量,但没有取消差异,只是把差异挪到了别人那里。

五、动手 Demo:系统调用与高级编程语言的可移植性

系统调用是程序请求操作系统办事的方式。 高级语言把这些调用包成一套写法,让你不用分别伺候每个系统。

import os
print("路径分隔符", repr(os.sep))
print("行尾换行  ", repr(os.linesep))
print("拼出来的路径", os.path.join("data", "a.txt"))

实跑输出:

--------------------------------------------------------------------
系统调用与高级编程语言的可移植性
--------------------------------------------------------------------

**系统调用=程序请求操作系统办事的方式。**
高级语言的作用,就是**把这些调用包成一套写法,让你不用分别伺候每个系统。**

  Python 的写法                  它对应什么           换系统要改吗
  -------------------------------------------------------------------------
  os.open/os.read/os.write     系统调用的薄封装     不用改,细节略有差异
  open/read/write              再加一层缓冲         完全不用改
  os.path.join                   按当前系统拼路径     完全不用改
  os.sep                         当前系统的分隔符     不用改,但值不一样

  实测眼前这套环境:

    路径分隔符      os.sep      = '\\'
    行尾换行        os.linesep  = '\r\n'
    拼出来的路径    os.path.join("data", "a.txt") = data\a.txt

  **换个系统,这三行的值都会变**——但调用它们的代码一行都不用改。
  这就是【可移植性】的具体含义:**差异被压在语言运行时那一层里了。**

实测 Windows 上:os.sep 是反斜杠、os.linesep 是回车加换行两个字符。 换个系统这两个值都会变,但调用它们的代码一行都不用改。

30 秒实验

  1. 把 os.sep 打印出来,再在纸上写出它在另一个系统上会是什么。
  2. 想一想:为什么有的库要专门标注【仅 Windows 可用】。

常见误区

  1. 以为可移植性等于【代码完全一样】。它是【要改的部分不用你改】。
  2. 以为可移植就不会有差别。细节差异仍在,只是被包住了。
自测三问(点开对答案) 1. 系统调用是什么? —— 程序请求操作系统提供服务的入口,如打开文件、申请内存、创建进程。 2. 高级语言怎么带来可移植性? —— 向上提供统一写法,向下分别调用各家的系统调用,把差异留在运行时里。 3. 可移植性的代价是什么? —— 只能用各家功能的交集、多层封装有开销,而且行为细节仍可能不一致。

相关笔记