进程的退出(main函数的退出)
main函数的返回值叫做进程的退出码,该退出码表示进程执行的情况。例如:一个函数返回一个值时,我们要知道函数的执行情况,可以去看函数的返回值。
例子:
1 #include<stdio.h>
2 int main()
3 {
4 return 10;//把返回值故意设置成10
5 }
运行后,使用 echo $? 查看最近一次进程结束的退出码
一般地,0表示进程执行成功,非0表示失败(与C++中0表示假,非0表示真相反),用不同的数字表示失败的原因。(这就是为什么用非0表示失败,0表示成功,因为0只有一个,表示成功不需要原因,而失败的原因有多种,可以用非零的多种数字来表示)。
错误码转化成错误描述,这样我们就知道进程终止的原因。
关于错误描述
1.使用语言和系统自带的方法,进行转换
我们打印Linux系统的错误码strerror和错误信息进行观察。
代码:
int main()
{
for(int i=0;i<200;i++)
{
printf("%d:%s\n",i,strerror(i));
}
return 10;
}
部分错误描述如下:
如图:0表示进程执行成功,1表示操作不被允许,2表示没有找到文件或目录……
2.自定义错误信息
我们可以进行自定义错误信息
6 enum{
7 success = 0,
8 open_err,
9 malloc_err
10 };
11 const char* errorToDesc(int code)
12 {
13 switch(code)
14 {
15 case success:
16 return "success";
17 case open_err:
18 return "file open error";
19 case malloc_err:
20 return "malloc error";
21 default:
22 return "unknown";
23 }
24 }
25 int main()
26 {
27 int code = malloc_err;
28 printf("%s\n",errorToDesc(code));
29 return code;
30 }
结果:
函数的退出(关于errno)
除了进程退出,函数退出,我们怎么知道函数执行情况?函数有返回值!这里与进程的退出极其类似。
调用函数,我们通常希望看到两种情况:
1.函数的执行结果——我们需要的返回值
2.函数的执行情况——成功,失败(什么原因)
通常根据函数的返回值就可以判断,该函数的执行情况是否成功,但是但我们需要知道函数为什么失败时就需要函数的错误码(类似于进程的退出码)。
进程退出的场景
1.代码运行完毕,结果正确
2.代码运行完毕,结果不正确
3.代码没有执行完,异常终止
其中前两个根据进程的退出码可以进行判断。 而第3条是进程收到了异常信号,每个信号都有不同的编号,而不同的信号编号表明了异常的原因。
结论:任何进程的最终执行情况,都可已使用两个数字(信号编号,退出码)表明具体的执行情况。
signumber(信号编号) | exit_code(退出码) | 情况 |
0 | 0 | 代码正常执行完,进程正常退出 |
0 | !0 | 代码跑完,结果不正确 |
!0 | !0 or 0 | 代码没有执行完,收到异常信号,退出码无意义 |
退出进程的常见方法
正常终止 | 异常退出 |
1.main返回(return) | ctrl+c,信号终止 |
2.调用exit | |
3.调用_exit |
exit()函数
头文件 stdlib.h
void exit(int status)
exit就是用来终止进程,在进程中任何地方调用,都可以终止进程。
status:进程退出时传的退出码。父进程通过wait来获取该值。
注:虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值 是255。
exit()是c语言提供的接口,c语言的库函数。
_exit()函数
头文件 unistd.h
void _exit(int status)
_exit也是是用来终止进程,在进程中任何地方调用,都可以终止进程。
status:进程退出时传的退出码。
_exit是系统调用接口。
_exit与exit的区别
1.exit支持刷新缓冲区,_exit不支持刷新缓冲区。
2.exit这个库函数封装了系统调用函数_exit.
为什么这样子?
c语言有这很高的跨平台性,原因之一就是c语言的库里面封装了不同平台的系统调用接口,在linux系统下封装了 linux的系统调用函数,在Windows下封装了Windows的系统调用函数,这样同一份代码在不同平台下都可以运行。