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()。
本文出自 “11275984” 博客,請務必保留此出處http://11285984.blog.51cto.com/11275984/1792913