【问题标题】:What is the difference between exit() and abort()?exit() 和 abort() 有什么区别?
【发布时间】:2010-09-28 15:58:10
【问题描述】:

在 C 和 C++ 中,exit()abort() 有什么区别?我正在尝试在出现错误(不是异常)后结束我的程序。

【问题讨论】:

    标签: c++ c error-handling exit abort


    【解决方案1】:

    abort 发送一个 SIGABRT 信号,exit 只是关闭执行正常清理的应用程序。

    您可以随心所欲地处理 abort 信号,但默认行为是关闭应用程序以及错误代码。

    abort 不会执行静态和全局成员的对象销毁,但 exit 会。

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

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

    看下面的例子:

    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 的析构函数。

    • 如果 abort 像上面这样注释:someobject destructor will be called 您将得到以下输出:

    退出函数2
    退出函数1

    【讨论】:

    • 这里调用exit function 2 THEN exit function 1. gcc 4, Linux 2.6.
    • atexit 的手册页显示:“[使用 atexit 注册的] 函数以相反的顺序调用;不传递任何参数。”
    • @strager 是对的,atexit 注册的函数应该在调用 exit 或 main 返回时以相反的顺序调用。
    • 运行测试,似乎在所有 atexit 回调之后调用了全局实例的析构函数。
    • +1 用于提醒人们即使在 abort() 调用之后操作系统最终也会释放所有分配的资源。
    【解决方案2】:

    abort() 退出程序而不首先调用使用atexit() 注册的函数,也没有首先调用对象的析构函数。 exit() 在退出你的程序之前两者都做。但它不会为自动对象调用析构函数。所以

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

    将正确地破坏ab,但不会调用c 的析构函数。 abort() 不会调用这两个对象的析构函数。不幸的是,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);

    【讨论】:

    • +1 因为,虽然 Brian R. Bondy 很好,但您确实提出了中止/退出的问题(不是调用的堆栈对象的析构函数),并为 RAII 密集型 C++ 进程提供了替代方案。
    • 我正在寻找一种无需调用 dtor 即可退出程序的方法,而您的答案正是我想要的!谢谢
    • 这当然是完全正确的,如果你的自动对象析构函数不被调用真的很重要:-)
    • 据我所知,exit 和 abort 之间的另一个区别是,abort 可能(取决于操作系统配置)导致生成核心转储。
    【解决方案3】:

    abort 发送SIGABRT 信号。 abort 不会返回给调用者。 SIGABRT 信号的默认处理程序关闭应用程序。 stdio 文件流被刷新,然后关闭。但是,C++ 类实例的析构函数不是(不确定这一点——也许结果未定义?)。

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

    【讨论】:

    • exit可以有多个通过atexit注册的回调函数,当exit被调用时,所有的回调函数都会按照注册时的相反顺序被调用。
    • @Gamble,当然,我在几分钟前对@Bondy 的回答的评论中提到了自己。我将编辑自己的答案以反映这一点。
    【解决方案4】:

    来自 exit() 手册页:

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

    来自 abort() 手册页:

    abort() 首先解除对 SIGABRT 信号的阻塞,然后引发该信号 调用进程的信号。这会导致进程异常终止,除非捕捉到 SIGABRT 信号并且该信号 处理程序不返回。

    【讨论】:

      【解决方案5】:

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

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

      abort() 函数将SIGABRT 信号发送到当前进程,如果它没有被捕获,程序将终止,但不能保证打开的流被刷新/关闭,或者通过tmpfile 创建的临时文件是移除后,atexit 注册的函数不会被调用,并且返回一个非零的退出状态给主机。

      【讨论】:

      • 嗯。该标准说,如果信号处理程序“不返回”,程序才不会终止。您对 C 非常熟悉。您能想象任何可以让它继续正常执行而不返回的场景吗?我想象 longjmp,但我不确定它在信号处理程序中的行为。
      • 一般来说,从信号处理程序调用 longjmp 是未定义的,但是当信号是通过 raise/abort 生成时有一种特殊情况,所以我想这在理论上是可能的,虽然我不认为我见过它完成。现在我将不得不尝试一下;)
      • 这似乎有效(由于 300 个字符的限制,分成多个帖子):#include #include #include #include 易失性 sig_atomic_t do_abort = 1; jmp_buf 环境; void abort_handler(int i) { do_abort = 0; longjmp(env, 1);}
      • int main(void) { setjmp(env); puts("在 setjmp"); if (do_abort) { 信号(SIGABRT, abort_handler); puts("调用中止");中止(); } puts("没有中止!");返回0; }
      • 在 Ubuntu 7.04 上打印: At setjmp Calling abort At setjmp Did not abort!
      猜你喜欢
      • 1970-01-01
      • 2016-12-08
      • 2014-10-08
      • 1970-01-01
      • 2010-12-20
      • 2017-04-14
      • 2013-03-30
      • 2011-08-15
      相关资源
      最近更新 更多