main 函数的返回值叫做进程的退出码。当进程成功退出的时候,我们一般用0来表示。进程失败的时候一般用非零来表示。我们使用不同的数字来表示进程退出时不同的失败原因。
我们查看系统的有多少退出码以及其含义时需要用到strerror() 他的头文件和用法如下。
通过一下代码来查看系统有多少退出码
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
int main()
{int i = 0;for(i;i<200;i++){printf("%d:,%s\n",i,strerror(i));}return 0;
}
我们可以看到系统大概有134个退出码,每个退出码都有其自己的含义。由于太长只列举出来前几个。
echo $? 查看最近一个进程的退出状态,查看到的是0 表示的就是成功。
同时我们还可以自己设置进程退出码以及它的含义。
enum{success=0,open_err,malloc_err
};const char* errorTodesc(int code)
{switch(code){case success:return "sucesss";case open_err:return "open_fail";case malloc_err:return "malloc_fail";dafault:return "unknow error";}}int main()
{int code = malloc_err;printf("%s\n",errorTodesc(code));return malloc_err;
}
除了进程退出,还有函数退出。 main函数退出表示进程结束,而函数退出仅仅表示函数调用完毕。函数也是有返回值的。调用函数一般我们通常想看到两种结果,第一函数执行结果 成功,或者失败。第二函数的执行情况,如打开一个文件,如果成功会返回一个文件指针,如果失败就会返回NULL。如:
打印出错误码,并且打印出错误原因。
通过以上我们列举的情况可以说明进程退出有三种情况
1.程序执行完,结果是正确的。
2.程序执行完,结果是错误的。
3.程序没执行完,程序就出现错误,结果无意义!!!
综上所述,只有当程序执行完的时候,结果才有意义。
进程出现退出是进程收到了异常的信号,每个信号都有不同的编号,每个编号都有自己的异常原因。
我们可以通过kill -l 查看有哪些信号:
我们这次主要了解 8 号 和 11号信号,8号信号相当与代码除0 ,而十一号信号相当于对野指针进行解引用。
exit:
exit是终止进程 其中status:是进程退出时候的退出码。
代码演示:
该进程只跑1秒就退出。
并且退出码显示为3。
同时,如果在while循环中调用一个函数,并且调用exit() 那么进程也会同样退出的。如下:
说明exit 是终止整个进程,在任意地方调用都是终止进程。
_exit 与 exit
他们两个的功能是一模一样的,exit是c语言给我们提供的接口,而_exit是linux系统给我们提供的接口,那么二者有什么区别呢?
看代码:
程序停止了3秒然后hello linux ,hello gm 才被打印到屏幕上。
_exit 并没有把hello linux ,hello gm 打印到屏幕上,
这是因为_exit 没有刷新缓冲去,而exit刷新了缓冲区,这也是他们的区别。
那么exit 和_exit 是什么关系呢。
exit 和 _exit 都是终止进程的,在整个系统中只有操作系统能够有权限来终止进程。
而_exit是系统调用接口,exit是c语言提供的库函数,库函数是不能终止进程的,只有操作系统提供的系统调用才能够终止进程,那么他们的关系就比较明确了。
就是exit在底层封装了_exit ,同时exit 中又添加了刷新缓冲区的功能。
为什么语言层面要进行封装呢?
第一:提高了语言的跨平台性。window系统,和Linux系统给我们提供的退出进程的接口肯定是不一样的(比如:函数名,函数参数,函数返回值)。所以Linux下的退出进程函数,在Windo ws下注定是跑不了的,造成代码的可移植性较差。所以c语言把系统调用接口在底层进行封装,在上层直接给一个exit函数。在Linux下使用Linux系统的调用接口给exit,在windows下使用windo ws的系统调用接口给exit,这样做在底层屏蔽了系统之间的差异,提高了可移植性、跨平台性。比如Java的虚拟机,python的命令行解释器,c/c++的库,都是为了解决跨平台而提出的解决方案。他们都会提供exit的功能,底层也封装了不同系统的系统调用接口。
第二:提高代码的可读性,降低程序员使用的门槛。