C標準定義了下面的退出函數:shell
#include <stdlib.h>緩存
void exit(int status);數據結構
void _Exit(int status);ide
int atexit(void (*function)(void));函數
函數功能介紹以下:測試
void exit(int status)spa
該函數終止調用的程序。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()。