Linux C語言退出函數詳解 C標準定義了下面的退出函數: #include <stdlib.h> void exit(int status); void _Exit(int status); int atexit(void (*function)(void)); 函數功能介紹如下: void exit(int status) 該函數終止調用的程式。status傳遞給系統用於父進程恢複。程式退出之前,exit()調用所有以atexit()註冊的函數,清空所有開啟的<stdio.h> FILE*流的緩衝區並關閉流,然後刪除所有由tmpfile()建立的臨時檔案。進程退出時,核心關閉所有剩下的已開啟檔案(即那些由open()、creat()或檔案描述符繼承開啟的檔案),釋放其地址空間,然後釋放所有其他使用的資源。exit()從不返回。 void _Exit(int status) 該函數基本上與POSIX的_exit()函數相同;我們稍後再對其進行介紹。 int atexit(void (*function)(void)) function是一個函數指標,指向程式退出時候調用的一個回呼函數。exit()在其關閉檔案和終止之前調用該回呼函數。這個想法在於程式能夠在最終關閉之前提供一個或者多個啟動並執行清理函數。提供一個函數被成為註冊該函數。 atexit()成功時返回0,出錯時返回-1並設定相應的errno。 下面的程式沒有有用的功能,但它示範了如何使用atexit(): void callback1(void){printf("callback called\n");} void callback2(void)(printf("callback called\n");} void callback3(void)(printf("callback called\n");} int main(int argc,char** argv) { printf("registering callback1\n");atexit(callback1); printf("registering callback2\n");atexit(callback2); printf("registering callback3\n");atexit(callback3); printf("exiting now\n"); exit(0); } 下面是程式的運行結果:
$atexit registering callback1 registering callback2 registering callback3 exiting now callback3 called callback2 called callback1 called 正如上例所示,使用atexit()註冊的函數運行時的順序和註冊的順序相反:最近註冊的最先運行(這也稱為後進先出(last-in-first-out),縮寫為LIFO)。 POSIX定義了_exit()函數。與exit()不同,exit()調用回呼函數並進行<stdio.h>清理,_exit()是“立即死亡”的函數: #include <unistd.h> void _exit(int status); _exit終止調用進程,但不關閉檔案,不清除輸出緩衝,也不調用出口函數。exit函數將終止調用進程。在退出程式之前,所有檔案關閉,緩衝輸出內容將重新整理定義,並調用所有已重新整理的“出口函數”(由atexit定義)。 實際上,ISO C的_Exit()函數與_exit()相同。C函數指出_Exit()是否調用以atexit()註冊的函數並關閉開啟的檔案取決與實現。對於GLIBC系統,可能不會,即_Exit()與_exit()表現相似。 使用_exit()的時機是在fork()產生的子進程中調用exec()失敗的時候。這種情況下,不需要使用通常的exit(),因為它會清空所有由FILE*流儲存的緩衝區資料。隨後父進程清空其緩衝區拷貝時,導致緩衝的資料被寫了兩次;顯然這不是很恰當。 例如,加入你運行了一個shell命令,並且自己調用fork()和exec()。代碼可能如下所示: char *shellcommand="..."; pid_t child; if((child=fork())==0){
execl("/bin/sh","sh","-c",shellcommand,NULL);
_exit(errno==ENOENT?127:126); } errno測試和退出值採取了POSIX shell所使用的慣例。如果要求的程式沒有退出(ENOENT——目錄中沒有它的項),則退出值為127。否則,檔案同樣退出,但由於其他原因不能夠被exec()執行,則退出狀態為126。在你自己的程式中採取這個慣例將會是個好主意。 簡言之,為了更好地使用exit()和atexit(),你應該遵循一下規則: 1、定義一個較小的退出狀態值的集合,你的程式使用該集合中的值與其調用者進行通訊。在你的代碼中使用#define常量或enum定義這些值。 2、決定是否有必要與atexit()一起使用回呼函數。如果有必要,則在main()中適當地方註冊這些函數;例如,在解析選項之後以及初始化任何回呼函數可能清除的資料結構之後,記住函數以LIFO(last-in-first-out)順序進行調用。 3、如果出錯,在任一地方都可以使用exit()從程式退出,退出是能夠發生的正確行為。同時使用你定義的錯誤碼。 4、main()函數是個例外,你可以在其中使用return。我們自己的風格是,通常出問題時使用exit(),而如果一切正常,在main()結尾處使用“return 0”。 5、如果調用exec()失敗,則在子進程中使用_exit()或_Exit()。