exit 和 exit 的區別

2021-08-19 01:51:12 字數 3753 閱讀 4960

exit()和_exit()的效果都是讓程式退出執行,而_exit()用來「盡快」退出。

先說一下atexit()函式。我們可以用atexit()註冊乙個或多個函式退出清理函式(或者on_exit()但這個函式不建議用),這些清理函式按照註冊時的反順序,在exit()或main函式return時被呼叫。

#include 

int atexit(void (*function)(void)); //return 0 on success.

注意,fork子程序時,這些函式會被繼承到子程序。而exec系列執行成功後,所有函式會被清空。

我們知道父程序要wait子程序的退出狀態,在子程序退出到父程序呼叫wait()期間,子程序就處於殭屍狀態。因此,exit()將程序正常退出,並將(status & 0377)返回到父程序的wait(),其中status可以是exit_success或exit_failure。

#include 

void

exit(int status);

exit()在返回到父程序前要做的事情包括:按出棧順序(反序)依次呼叫atexit()/on_exit()註冊的函式。然後將所有開啟的stdio流進行flush並關閉,如果有通過tmpfile()建立的檔案也會被刪除。(這裡要注意,如果你註冊的某個清理函式中呼叫_exit()或把自己kill結果退出了,那麼後面的清理函式以及刷stdio等就不會執行了。所以,清理函式裡不要呼叫exit()或_exit()。)

子程序exit()後會傳送乙個sigchld訊號給父程序(如果父程序設定了sa_nocldwait,那這個訊號是否傳送是未定義的)。

如果子程序在exit()後,父程序已經在等待(wait()系列函式)子程序的狀態,或者父程序設定了sa_nocldwait或者將sigchld的處理置為sig_ign,子程序都會立即退出。而如果父程序既沒有wait,又沒有設定忽略子程序退出,子程序就會變成殭屍程序(除了乙個位元組的exit status,什麼都沒有,用來確保以後某個時刻父程序wait的時候仍能拿到status,來解除子程序的殭屍狀態)。如果父程序到死都沒有wait,那殭屍程序會被init收養然後用wait清理掉它。

#include 

void _exit(int status);

當然,由於_exit()會關閉檔案描述符,所以可能也會有些delay(例如還沒寫完就close),如果想達到「立即」的目的,在_exit()之前呼叫一下tcflush()可能會有幫助。

在main()函式裡呼叫exit()或return都可以使程式退出,但二者有一些差別:

-return是返回到main的呼叫者(如_libc_start_main),main()函式棧出棧,相關的區域性變數被釋放,呼叫者函式再讓程式退出;

-exit()則是直接進入exit()函式去執行並退出函式。

無論哪種方式,它們都會呼叫exit_group(status)系統呼叫來讓整個程序退出,其中引數status就是要發給父程序的狀態碼,即 exit(status) 或 return status; 中的status。

通常我們在main()之後就沒什麼待辦的事情了,也不會關心exit()和return的差別,但對於c++程式而言,main()中物件的析構函式是在return之後執行的,如果中途調了exit()就不會執行到析構函式。

我們看下面這個程式:

#include 

#include

#include

using

namespace

std;

void exit_func(void)

class date

void printdate()

int isleapyear()

void setdate(int year, int month, int day) {}

~date()

private:

int year;

int month;

int day;

};class a

~a()

};class b

~b()

};static date d199;

int main(int argc, char *argv)

這個程式中有幾點需要關注:1.定義了乙個全域性的物件d199,我們知道全域性物件的構造是在main()之前做的,相應的全域性物件或區域性靜態物件的析構在main()之後。2.我註冊了乙個atexit函式exit_func(),上面講過它會在main()之後被執行。3.在main()函式最後我呼叫了return 0。

執行程式:

[root@ubuntu]diskroot:$ c++ newmain.c 

[root@ubuntu]diskroot:$ ./a.out

date constructor

main

start

date

constructor

2014:

1:31

date constructor

a'sconstructor

a'sconstructor

b'sconstructor

main

done

b'sdestructor!

a'sdestructor!

a'sdestructor!

date

destructor!

ohyeah!

date

destructor!

date

destructor!

可以看到,**執行順序是:全域性物件的構造 -> 進入main() -> main()中物件的構造 -> main()返回 -> main()中物件的析構 -> atexit註冊的退出函式 -> 全域性和區域性靜態物件的析構。

接下來我們再看一下把 return 改為 exit 的結果(其他**不變):

[root@ubuntu]diskroot:$ c++ newmain.c 

[root@ubuntu]diskroot:$ ./a.out

date constructor

main

start

date

constructor

2014:

1:31

date constructor

a'sconstructor

a'sconstructor

b'sconstructor

main

done

ohyeah!

date

destructor!

date

destructor!

可以看到,main()中定義的物件的析構沒有被呼叫。

一般情況下,析構函式就是釋放物件的資源,而程序退出後,程序所有資源就都被釋放了,所以實際上呼叫exit()退出程式也並不會出現資源洩漏。只是說如果你的析構函式會涉及到與其他程序通訊或io操作等影響到系統其他資源的情況下就要注意了。

另外由於使用return的話,main()函式返回,其函式棧被釋放,這對於vfork()會導致父程序還沒用完的棧被破壞。不過vfork()已經不被使用了,現在的fork()也不是當年發明vfork()時的那個低效的fork()了,所以這個問題我們不用關心。

在main()最後什麼都不寫也就相當於return 0, 當然不建議這樣寫,最好還是明確返回值退出。

exit和exit的區別?

exit終止呼叫程序,但不關閉檔案,不清除輸出快取,也不呼叫出口函式。exit函式將終止呼叫程序。在退出程式之前,所有檔案關閉,緩衝輸出內容 將重新整理定義,並呼叫所有已重新整理的 出口函式 由atexit定義 作為系統呼叫而言,exit和exit是一對孿生兄弟,它們究竟相似到什麼程度,我們可以從l...

exit和exit的區別

在linux的標準庫函式中,有一套稱作高階i o的函式,我們熟知的printf fopen fread fwrite都在此列,他們也被稱作緩衝 i o。其特徵是對應每乙個開啟的檔案,都存在乙個緩衝區,在記憶體中都有一片緩衝區,每次讀檔案會多讀若干條記錄,這樣下次讀檔案時就可以直接從記憶體的快取中取出...

exit和exit的區別

在linux的標準庫函式中,有一套稱作高階i o的函式,我們熟知的printf fopen fread fwrite都在此列,他們也被稱作緩衝 i o。其特徵是對應每乙個開啟的檔案,都存在乙個緩衝區,在記憶體中都有一片緩衝區,每次讀檔案會多讀若干條記錄,這樣下次讀檔案時就可以直接從記憶體的快取中取出...