目录
进程终止
下面要谈的一个话题就是进程终止,就是说一个进程退出了,可能有三种情况
1.进程代码执行完,结果是正确的
2.进程代码执行完,结果是错误的
3.进程代码没有执行完,进程出异常了,中途退出了
其实我们写的main函数执行起来就是一个进程,而我们一般写的return 0,就叫做进程的退出码。一般0表示正确执行,第一种情况;而非0表示执行失败,第二种情况。因为main函数的return 0就已经是代码的最后部分了。
为什么用非0表示执行失败呢?因为成功就是成功了,而失败可能会有很多种原因。进程的退出码是给机器看的,要是给人看,就要把退出码转化成错误描述,这个错误描述可以是系统或语言自带的,也可以自定义,下面我们先用strerror函数看一下系统中的错误描述
我们可以看到有很多错误描述,到133个了
这时我们就能解释我们瞎给比如ls 后面一个选项,bash进程,就是命令行解释器报的错是什么了,比如:
这不就是上面的二号错误吗,另外,下面的指令可以查看最近一次进程的退出码
为什么第二次用显示0呢?因为echo $?也是一个进程,它是成功执行的
我们上面说也可以自定义,那就可以创建几个字符串枚举值,并且枚举值是可以表示整数的,这样就可以自己去定义错误码了,比如:
上面我们说了前两种情况,第三种情况是进程没有执行完,中途出现异常了,只要中间出现异常,其实结果对与否就没有意义了。其实中途出现异常本质上就是进程收到了异常信号,就是kill -l那一系列的信号
比如:
8号信号对应的是
SIGFPE
(Floating-Point Exception)信号。这个信号用于指示浮点运算异常,比如除以零或溢出等情况。11号信号对应的是
SIGSEGV
(Segmentation Fault)信号。这个信号用于指示进程发生了内存段错误,即试图访问无效的内存地址。
并且有一个细节就是这些错误是从1开始的,这跟我们下面的如何用16比特位表示退出码和收到什么信号是有关系的,并且这些大写的字母都是宏定义。
所以进程执行的情况可以由两个数字表示,一个是收到什么信号(0就表示没有收到信号),一个是退出码。
errno
除了进程退出,就是main函数退出,我们还有普通函数退出,那我们如何知道它的运行情况呢?我们也有个存放错误码的东西,叫errno,就是说,函数如果执行失败的话,那么错误码会放在erron这个整形变量里,这个一般库函数才会有这个错误码,因为库函数内部一般是有这个赋值的,我们一般写的函数没有,比如fopen,可以看一下它的返回值
可以看到errno这个东西,下面写一个代码看一下
其实我当前目录根本就没有这个文件,并且是以只读的方式打开文件,所以它肯定会出错,错误信息就存在errno里面,我们也可以看具体字符信息,运行之后就是这样
exit和_exit
我们如果想让一个进程退出可以用exit或_exit,前者是库函数,后者是系统调用,我们可以来查一下
这里的参数status就是你想让进程退出时的退出码,我们通过一段代码来展示一下它们的区别
我们写这样一个代码,运行完后发现什么都不打印,而把_exit改成exit后就会打印,这就说明exit会刷新缓冲区,其实exit就是封装了_exit,为什么要这样做呢?
其实我们知道库函数和系统调用是上下层关系,不同的操作系统的系统调用是不同的,比如Windows下_exit就用不了,所以这时我们把系统调用再封装一层成为库函数,不同的操作系统封装不同的系统调用,但是它们的库函数的接口就是一样的了,这就通过库函数屏蔽掉了系统调用的差异,就实现了语言的可移植性和跨平台性,所以不同的操作系统就会安装不同的库文件。并且这里的缓冲区是库级别的缓冲区,所以系统调用是无法刷新的,如果是操作系统级别的,那就会刷新,因为操作系统不会让它白白占着空间的。