系统呼叫:
1. 小明打算写一个
回声机
程序
,
它的功能很简单:用户从
键盘
输入什么话,它就在
屏幕
回响什么话。小明一琢磨:这个程序大体上细分为两个步骤:
-
第一步:从键盘读取输入序列(比如一个一个字符地读取输入序列),把它们临时存放到内存某个位置
-
第二步:读取内存位置M,把字符输出到屏幕上
小明再三审视,觉得很严谨了,他决定动手了,他选择
C语言
来完成这个项目。
2. C作为古老的编程语言,它遵从的是
面向过程式的编程范式,
也就是一开始小明一开始思考的步骤,步步为营,一步一个脚印。这是很符合人类大脑的最简单的行事逻辑的。 那么第一步首先是,处理输入序列。小明又开始琢磨了,他发现原来这件事还可以再细分:
-
第一步1:敲击键盘的动作触发某种电信号
-
第一步2:电信号以某种机制告知CPU
-
第一步3:CPU以某种方式把电信号进行转换
-
第一步4:把转换的信号以某种二进制格式,存放于内存某个位置
3.小明开始有些挠头了,他没学过电路知识,也不懂CPU响应外部信号的机制,如何编写。 幸好,一番
搜索查找资料,
他发现:原来这些东西早就有人做好了,这是
操作系统
的功能之一:它
抽象了复杂的机器硬件逻辑
,然后提供了一件叫做
系统调用(
其实因该叫核心
)
的东西, 他在写程序时只要
调用
就可以。
4.但他发现:没有什么公开的函数供他调用,以实现第2步中的分别四个小步骤啊。这不坑爹嘛!!!
于是,小明又
一番搜索
,发现:原来, 这种系统调用还是相当抽象繁复的,一般人难以理解,更别说使用了,而且它也不符合人们的思维逻辑,人类只有输入一个东西,再把它原样输出这个概念,哪有这些乱七八糟的什么电路,CPU的概念啊。 进一步的说,他发现
抽象是有层次的,
原来存在着更高级抽象, 人们可以直接使用来从键盘获取输入!(
这才是系统呼叫,可以理解成为高级语言的应用程序api
)
5. 这个
更高级抽象
就是C语言中的
标准输入输出库.
好家伙, 从这名字看,貌似输出这个库也帮他搞定了!
善于思考
的小明又想多一些:
-
这种所谓的库,不仅屏蔽了细节,因为不同的键盘,不同的CPU,可能处理这些信号转换的方法是不同的。用一个库来封装,只提供给外界声明好的确定的接口,外界就可以拿它来用了,而根本不用关心底层是如何实现的!要不换一台机器, 小明就得又大费周章去重写代码。 真妙!
-
另外, 计算机作为一种机器,它也存在接口,叫做人机界面,接收外界的输入及向外界输出。这种行为应该是十分常见的,用一个库把这个行为封装起来,事半功倍啊!造福人人的啊喂!
6. 小明真正开始编写代码了,他发现, 原来所有前面的工作只要一句话:
#include<stdio.h>.
它表示:
-
那个编译器啊,我要的功能在一个叫stdio(STanDard Input / Output)的库里, 我要用它。
-
至于这个叫stdio库是做什么的,它已经提供了一份清单了,叫stdio.h, 里面记录了它提供给外界的所有接口。
-
我等下要用一个叫scanf 和 printf 的接口,这个接口的声明就在这个stdio.h文件里,你去核对下, 要是我用错了,你告诉我一声。
编译器:
好的,没问题!
7
. 就此刻为止,小明已经获得了他想要的。至于后面的故事嘛,编译器又去跟一个叫
链接器
的家伙
通信
(当然以他们之间能理解的协议),告诉链接器,去把一个叫
stdio库
的家伙中的
scanf和
printf代码
以某种方式链接
进最后的可执行文件里。
8. 回顾整个过程,小明的计划:
-
步骤清晰(每一个步骤做什么很清楚)
-
分划干净(每个步骤只做一件事,各个步骤间通过协定的协议通信,比如1与2之间的协议是把某种击键电信号转换为内存中对应的字符,2与3之间的协议是把内存中的存放的字符转换为屏幕上一个方块的点阵图案)
于是,不经意间,小明已经完成了对
面向过程编程(8.1)
与
模块化(8.2)
的一次体悟.
小明的思考过程涉及了两个重要方面,而这不仅是编程模式的思考,更是人类对这个复杂外界环境的思考与抽象。 而编程,不过是以另一种语言的方式再现这种思考而已!