一、main函数的返回值
我们在编写C语言的程序时,通常会这样写:
int main()
{
return 0;
}
那么我们为什么要返回(return)0 呢?
其实,main函数也是一个函数,它也会被调用,所以谁调用main函数,这个返回值就会返回给谁。
我们写一个test.c来观察:
#include<stdio.h>
int main()
{
//code
return 3;
}
执行以上程序,我们可以看到return返回值写的是3。
我们可以通过 echo $? 查看进程退出码:
- main函数的 返回值,就叫做进程的退出码。
- 0 -> sucess (0表示成功)
- !0 -> failed (!0表示失败);此时我们就可以用不同的数字表示不同的原因
main函数的退出码是可以被父进程获取的,用来判断子进程的运行结果。
注:
纯数字虽然能表明出原因,但是不便于人类的阅读,所以我们将 exit code -> exit code string(可以用内置的,也可以自定义)
例:打印Linux中的错误码信息(根据运行结果可以看出有133个)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//code
int i = 0;
for(i = 0; i < 200; i++)
{
printf("%d: %s\n", i, strerror(i));
}
return 3;
}
我们运行的mybin文件就是bash的子进程。子进程退出时,退出码会被它的父进程自动获得。
echo $? 中,?中保存的是最近一个子进程执行完毕时的退出码。
例:
错误码是127
错误码是1
错误码与退出码
- 错误码通常是衡量一个库函数或者是一个系统调用、一个函数的调用情况
- 退出码通常是一个进程退出的时候,它的退出结果
相同的是,当失败的时候,用来衡量函数、进程出错时的出错详细原因。
二、进程终止
1、进程退出场景
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
异常:
进程出现异常,本质是进程收到了对应的信号,自己终止了。
例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char* p = NULL;
*p = 1;
return 0;
}
运行后:
出现异常后,操作系统会根据发送的信号将该进程杀死。
Linux中:
那么,我们可以通过发送信号来终止一个进程 :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("进程: %d\n", getpid());
sleep(1);
}
return 0;
}
程序运行:
此时,我们可以通过kill -11 27747 杀死该进程 (以 -11 为例,也可以是其它信号):
因此,一个进程是否出异常,我们只需看有没有收到信号即可。
2、exit(进程的退出码)
(任何时间,任何地点,exit,随时结束!)
任意地点调用exit,都表示进程直接退出,不进行后续执行。
exit:
1. 执行用户通过 atexit或on_exit定义的清理函数。
2. 关闭所有打开的流,所有的缓存数据均被写入
3. 调用_exit
例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main()
{
printf("test\n");
exit(13);
return 0;
}
3、_exit和exit
- exit是库函数,_exit是系统调用
- exit终止进程的时候,会自动刷新缓冲区;_exit终止进程的时候,不会自动刷新缓冲区
注:缓冲区不在操作系统内部。