在C ++中使用exit
有question。答案讨论主要是因为RAII不是好主意,例如,如果在代码中某处调用exit
,则不会调用对象的析构函数,因此,例如,析构函数是为了将数据写入文件,这不会发生,因为没有调用析构函数。
我感兴趣的是C中的这种情况。类似的问题是否也适用于C?我想在C中我们不使用构造函数/析构函数,C中的情况可能不同。那么在C中使用exit
是否可以?
我见过下面的函数,在某些情况下我觉得很好用,但是如果我们在使用exit
的C中遇到类似的问题感兴趣,如上面用C ++所述? (这将使使用下面的功能不是一个好主意。)。
void die(const char *message)
{
if(errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
答案 0 :(得分:82)
而不是abort()
,C中的exit()
函数被认为是一个优雅的"退出。
来自C11(N1570)7.22.4.4/p2 退出功能(强调我的):
exit
功能会导致正常程序终止。
标准还在7.22.4.4/p4中说:
接下来,所有打开的未写入缓冲数据的开放流都会被刷新 开放流已关闭,以及
tmpfile
功能创建的所有文件 被删除。
还值得一看7.21.3 / p5 Files :
如果
main
函数返回其原始调用方,或者exit
函数被调用,所有打开的文件都被关闭(因此所有输出 在程序终止之前刷新流。其他途径 程序终止,例如调用abort
函数,不需要 正确关闭所有文件。
但是,正如下面的评论中所述,您无法假设它将涵盖所有其他资源,因此您可能需要诉诸atexit()
并为其发布定义回调个别。实际上它正是atexit()
的意图,正如7.22.4.2/p2 atexit函数中所述:
atexit
函数注册func
指向的函数 正常程序终止时不带参数调用。
值得注意的是,C标准没有准确说明分配的存储持续时间(即malloc()
)对象应该发生什么,因此要求您了解如何在特定实现上完成。对于面向主机的现代操作系统,系统很可能会处理它,但您仍可能需要自己处理这个问题,以便使Valgrind等内存调试器静音。
答案 1 :(得分:22)
是的,可以在C中使用exit
。
为了确保所有缓冲区和正常有序关闭,建议使用此函数atexit
,有关此here的更多信息
示例代码如下:
void cleanup(void){
/* example of closing file pointer and free up memory */
if (fp) fclose(fp);
if (ptr) free(ptr);
}
int main(int argc, char **argv){
/* ... */
atexit(cleanup);
/* ... */
return 0;
}
现在,每当调用exit
时,函数cleanup
将被执行,这可以保持正常关闭,清理缓冲区,内存等。
答案 2 :(得分:14)
您没有构造函数和析构函数,但您可以拥有资源(例如文件,流,套接字),并且正确关闭它们非常重要。无法同步写入缓冲区,因此在未正确关闭资源的情况下退出程序可能会导致损坏。
答案 3 :(得分:9)
exit()
可以尚未提及的代码设计的两个主要方面是“线程”和“库”。
在单线程程序中,在您编写的代码中实现该程序,使用exit()
就可以了。当程序出错并且代码无法恢复时,我的程序会定期使用它。
但是,调用exit()
是一项无法撤消的单方面行动。这就是'线程'和'图书馆'需要仔细考虑的原因。
如果一个程序是多线程的,那么使用exit()
是一个戏剧性的动作,它会终止所有线程。退出整个程序可能不合适。退出线程,报告错误可能是适当的。如果您认识到该计划的设计,那么也许允许单方面退出,但总的来说,这是不可接受的。
并且“认识到程序设计”条款也适用于库中的代码。通用库函数调用exit()
很少是正确的。如果其中一个标准C库函数由于错误而无法返回,那么你有理由感到不安。 (显然,exit()
,_Exit()
,quick_exit()
,abort()
等函数不会返回;这是不同的。)因此,C库中的函数“不能”失败“或以某种方式返回错误指示。如果您正在编写代码以进入通用库,则需要仔细考虑代码的错误处理策略。它应该适合与其一起使用的程序的错误处理策略,或者可以使错误处理可配置。
我有一系列库函数(在包含标题为"stderr.h"
的程序包中,这个名称位于薄冰上),它们在用于错误报告时会退出。这些功能按设计退出。在同一个包中有一系列相关的函数报告错误而不退出。当然,现有功能是根据非退出功能实现的,但这是一个内部实现细节。
我有许多其他库函数,其中很多都依赖"stderr.h"
代码进行错误报告。这是我做出的一个设计决定,也是我很满意的。但是当使用退出的函数报告错误时,它会限制库代码的一般用途。如果代码调用了不退出的错误报告函数,那么函数中的主代码路径必须明智地处理错误返回 - 检测它们并将错误指示转发给调用代码。
我的错误报告包的代码在GitHub上的SOQ(堆栈溢出问题)存储库中可用作src/libsoq子目录中的文件stderr.c
和stderr.h
。
答案 4 :(得分:6)
在exit
以外的函数中避免main()
的一个原因是您的代码可能会脱离上下文。请记住,退出是一种非本地控制流。像无法捕获的例外。
例如,您可能会编写一些在关键磁盘错误时退出的存储管理功能。然后有人决定将它们移到图书馆。退出库会导致调用程序以不一致的状态退出,而该状态可能没有准备好。
或者您可以在嵌入式系统上运行它。没有地方可以退出到,整个事情都在while(1)
的{{1}}循环中运行。它甚至可能没有在标准库中定义。
答案 5 :(得分:2)
根据你正在做的事情,退出可能是C中程序最合乎逻辑的方式。我知道检查以确保回调链正常工作非常有用。以我最近使用的这个回调为例:
unsigned char cbShowDataThenExit( unsigned char *data, unsigned short dataSz,unsigned char status)
{
printf("cbShowDataThenExit with status %X (dataSz %d)\n", status, dataSz);
printf("status:%d\n",status);
printArray(data,dataSz);
cleanUp();
exit(0);
}
在主循环中,我为此系统设置了所有内容,然后等待一段时间(1)循环。可以使用全局标志来退出while循环,但这很简单,并且可以做它需要做的事情。如果您正在处理任何打开的缓冲区,如文件和设备,您应该在关闭之前清理它们以保持一致性。
答案 6 :(得分:-1)
在一个大项目中,除了coredump之外,任何代码都可以退出,这很糟糕。 Trace对于维护在线服务器非常重要。