要说明这点,先要说一下什么是用户程序,什么是系统程序。
为了限制用户程序的权限,和将一些系统操作抽象出来,计算机系统将一些高等操作称为系统程序,如申请内存,读取内存信息到寄存器/读取磁盘信息到内存,从一个外部设备读取信息到磁盘,等。
同时这样分离还有一个好处,就是提高系统的吞吐率。众所周知,cpu寄存器-一级缓存-二级缓存-内存-磁盘-网络存储设备,越往后读取的速度越慢,而让cpu盲目的等待IO的数据到位,然后再执行后续的程序,是极其浪费cpu计算资源的。而另一方面,由于计算机系统的多进程特性,一个用户程序在一个进程调用系统程序,进行耗时的IO时,完全可以对这个进程进行挂起,让cpu资源去处理其他进程的逻辑,待IO完毕,给挂起的程序一个通知,让挂起的程序继续进行IO后的逻辑。
这种通知进程的行为,就是异常,而这个通知,就是后面要讲到的信号。
计算机系统的异常有4种:中断,陷阱,故障,终止
中断
中断通常发生在用户程序和硬件交互。中断的过程是异步的,即发生中断时用户程序被挂起(被中断了),待硬件返回后,用户程序继续发生中断代码后续的命令。
陷阱
陷阱和中断类似,只不过陷阱是同步的。陷阱像是一种故意的异常,发生在软件程序上的调用,如用户程序向系统程序申请fock一个子进程,或者执行另外一个程序。所以实现系统程序的封装和系统程序和用户程序的隔离,接口化,使用的也是陷阱这种异常。
故障
故障是由于错误引起的。故障发生时,程序的控制转移到故障处理程序,待故障处理程序逻辑结束后,程序计数器会尝试回到故障出现的行命令。一个典型的故障就是内存缺页故障。当程序读取内存的某一个虚拟地址,发现读取的内存页面不在内存里面,于是引起缺页故障,处理程序将数据从磁盘读取到内存对应的页面,故障处理结束,程序再次回到读取内存页面的那行,这时候,读取的代码再次执行,就可以正常运行了。
终止
终止发生在程序出现致命错误的时候,系统在执行完故障处理程序后,会停止该程序。如:内存损坏时。
信号有很多种类型,系统给不同的信号定义了不同的意义,其中也保留了用户可以自定义的信号

(图出自<<Computer Systems Third edition»)
比如在当前进程按下ctrl+c..实际上就是键盘通过操作系统给当前进程发送了一个2信号
通过kill命令,传入信号和进程id,可以给进程发送一个信号。常见的nginx通过kill命令重启nginx,平滑重新加载配置,就是用了这个特性。
在程序逻辑里,可以调用c的kill函数给进程id传入信号。如果进程id大于0,向进程id发送信号;如果进程id为0,则为自己和自己所在的进程组每个进程发送信号;如果进程id小于0,则为进程id的绝对值以及进程id绝对值所在的进程组所有的进程都发送信号。

(图出自<<Computer Systems Third edition»)
在程序逻辑里面,用户也可以注册信号的handler函数,当进程被传入信号时,程序控制就会交给handler函数。处理完后,控制交还给故障发生时的后一句命令,程序继续执行。

(图出自<<Computer Systems Third edition»)
c语言提供setjump和longjump方法。setjmp方法保存当前进程的运行状态(包括程序计数器,栈指针和通用目的寄存器),而longjmp根据之前保存的状态还原程序执行的状态,继续执行setjmp处后面的逻辑。
高级语言的异常捕捉trycatch,或者说php的yield,实际上是setjmp longjmp的封装:在catch处setjmp,然后执行try里面的代码段,throw时调用longjmp。
无论是保存在硬盘里面作永久储存,还是保存在内存/寄存器里面作为计算的临时储存,信息在计算机里面需要一个表示方法,或者叫做保存方法.
首先,可以先来看一下c语言都有哪些信息的类型,或者说我们编程时候都用到哪些信息类型:
其中,布尔型可以用简单的 整型0&整型1 表示,就不单独说明.
由于一些基本的概念,比如字符串用ASCII码/UTF-8编码表示,整型根据不同的长度有,是否有符号,会有不同的范围,下面只挑选不同信息类型(或者叫数据类型)的值得提一下的点作说明.
整型无符号形式不用多说,而有符号的表示形式除了简单的使用最高位作为符号位(1000 0001 表示-1),还有两种表现形式:补码表示和反码表示.
实际上,补码相对于原码和反码,对于计算机的计算是更优化的.大多数现代计算机都用补码表示有符号数.
补码中, 如 1000 0001,将最高有效位解释成负权,而后, 所以 1000 1111 = **-**2^7 **+**2^3 **+**2^2 **+**2^1 **+**2^0 = -113
而反码就与补码类似,不过补码的负权为 - 2 ^(w-1), 反码的负权为 -2^(w-1) - 1, 其中w为整型长度
补码相比反码和原码(即最高位表示符号位的形式)的差别在于:
补码的0000 0000表示0,没有-0表示,而反码和原码都存在一个-0表示 (反码为1111 1111, 原码为 1000 0000)
补码的加减乘除运算,都等价于将补码转换为无符号数的加减乘除,再转换回补码,而反码和原码都要先作相应的转换.(至于为什么反码和补码不能直接运算,可以参考这个文章: 原码, 反码, 补码 详解)
书中介绍了一种浮点型表示的标准: IEEE浮点表示.
IEEE浮点表示用是三部分来表示一个浮点数: 符号位,尾数,阶码
其中,符号位s直接编码正负; 尾数和阶码编码浮点数的两部分值得: 指数E和小数M…浮点数V可以表示为: V = (-1)^s * M * 2^E