exit()和abort()有什么区别?


Answers:


116

abort()退出程序而无需先调用使用其注册的函数atexit(),也无需首先调用对象的析构函数。exit()在退出程序之前都执行这两项操作。但是,它不会为自动对象调用析构函数。所以

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

将破坏ab正确地进行,但不会调用的析构函数cabort()不会调用这两个对象的析构函数。不幸的是,C ++标准描述了一种可确保正确终止的替代机制:

具有自动存储期限的对象都在程序中被销毁,该程序的功能不main()包含自动对象,并执行对的调用exit()。可以通过main()引发捕获到的异常将控制权直接转移到此类main()

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

而不是调用exit(),而是安排该代码throw exit_exception(exit_code);


2
+1是因为,尽管Brian R. Bondy很好,但是您确实提出了中止/退出(不是称为堆栈对象的析构函数)的问题,并为RAII密集型C ++进程提供了替代方案。
paercebal

我一直在寻找一种无需调用dtor即可退出程序的方法,而您的答案正是我想要的!谢谢
acemtp

当然,如果您不自动调用对象自动析构函数真的很重要,那是完全正确的:-)
Chris Huang-Leaver 2010年

据我所知,退出和中止之间的另一个区别是,中止可能(取决于操作系统配置)导致生成核心转储。
Dirk Herrmann,

33

中止发送SIGABRT信号,退出仅关闭执行常规清除的应用程序。

您可以根据需要处理中止信号,但是默认行为是使用错误代码关闭应用程序。

abort将不会对您的静态成员和全局成员执行对象破坏操作,但是将退出

当然,尽管在应用程序完全关闭时,操作系统将释放所有未释放的内存和其他资源。

终止退出程序的过程中(假设您没有覆盖默认行为),返回代码将返回到启动应用程序的父进程。

请参见以下示例:

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

注释:

  • 如果取消注释abort:不打印任何内容,并且不会调用某对象的析构函数。

  • 如果中止的注释如上:将调用someobject析构函数,您将获得以下输出:

退出功能2
退出功能1


在这里,它称为退出函数2 THEN退出函数1. gcc 4,Linux 2.6。
斯特拉格

1
atexit的手册页说:“以相反的顺序调用[使用atexit注册的功能];不传递任何参数。”
斯特拉格

@strager是正确的,当调用exit或main返回时,应该以相反的顺序调用atexit注册的函数。
罗伯特·格兰伯

进行测试,似乎在所有atexit回调之后都调用了全局实例的析构函数。
斯特拉格

+1提醒人们,即使在abort()调用之后,操作系统最终仍将释放所有分配的资源。
Fingolfin

10

程序调用exit()时会发生以下情况:

  • atexit执行功能注册的功能
  • 刷新并关闭所有打开的流,tmpfile删除创建的文件
  • 程序以指定的退出代码终止到主机

abort()函数发送SIGABRT信号到电流过程中,如果它没有被捕获该程序终止于不能保证打开的流被刷新/闭合或经由创建的临时文件tmpfile被移除,atexit注册功能不叫,和非零退出状态返回到主机。


嗯。该标准说,只有在信号处理程序“不返回”时程序才不会终止。您对C非常满意。您能想象有什么方案可以使它继续正常执行而不会返回吗?我想象longjmp,但我不确定它在信号处理程序中的表现。
Johannes Schaub-litb

通常,从信号处理程序中调用longjmp是未定义的,但是在特殊情况下,何时使用抬高/中止生成信号,因此我认为从理论上讲这是可能的,尽管我认为我从未见过这样做。现在我将不得不尝试;)
罗伯特·甘布尔

1
这似乎可行(由于300个字符的限制,分成多个帖子):#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> volatile sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler(int i){do_abort = 0; longjmp(env,1);}
罗伯特·

int main(void){setjmp(env); puts(“ At setjmp”); 如果(do_abort){signal(SIGABRT,abort_handler); puts(“调用中止”); abort(); } puts(“没有放弃!”); 返回0; }
Robert Gamble

在Ubuntu 7.04上,此打印:在setjmp调用中止在setjmp没有中止!
罗伯特·格兰伯

5

从exit()手册页:

exit()函数导致正常进程终止,并且状态&0377的值返回给父级。

在abort()手册页中:

abort()首先取消阻止SIGABRT信号,然后为调用过程引发该信号。除非捕获到SIGABRT信号并且信号处理程序不返回,否则这将导致过程异常终止。


4

abort发送SIGABRT信号。 abort不返回到呼叫者。SIGABRT信号的默认处理程序将关闭应用程序。 stdio文件流被刷新,然后关闭。但是,没有C ++类实例的析构函数(不确定这一点-可能结果不确定吗?)。

exit有自己的回调,设置为atexit。如果指定了回调(或仅指定一个),则以与注册顺序相反的顺序(如堆栈)调用它们,然后程序退出。与一样abortexit不会返回到调用方。 stdio文件流被刷新,然后关闭。同样,将调用C ++类实例的析构函数。


exit可以通过atexit注册多个回调函数,当调用exit时,所有回调函数将以注册时的相反顺序调用。
罗伯特·格兰伯

@Gamble,当然,我在几分钟前提到@Bondy的答案时提到了自己。我将编辑自己的答案以反映这一点。
斯特拉格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.