C語言中的程序終止函數


在C語言的標准庫<stdlib.h>中提供了一些與正常或者不正常的程序終止有關的函數,下面分別對其進行簡單介紹。

參考文獻:

[1] C和指針,P298,342

[2] C程序設計語言現代方法(第2版),P489

[3] atexit函數和exit函數的理解 

 

1 abort()

  abort()函數用於不正常地終止一個正在執行的程序。函數原型如下:

void abort(void)

  這個函數將引發SIGABRT信號,你可以在程序中為這個信號設置一個信號處理函數,在程序終止(或干脆不終止)之前采取任何你想采取的動作,甚至可以不終止程序。

  abort()函數類似於exit()函數,但調用它會導致異常的程序終止。atexit()函數注冊的退出函數不會被調用。根據具體的實現,它可能不會清理包含未輸出數據的輸出緩沖區,不會關閉打開的流,也不會刪除臨時文件。abort()函數返回一個由實現定義的狀態碼來指出“不成功的終止”。

補充:

  調用abort()函數時,實際上會產生SIGABRT信號。如果沒有處理SIGABRT信號的函數,那么程序會如前所述那樣異常終止。如果(通過調用signal()函數)為SIGABRT安裝了信號處理函數,那么就會調用處理函數。如果處理函數返回,隨后程序會異常終止。但是,如果處理函數不返回(比如它調用了longjmp()函數),那么程序就不會終止。

 

2 atexit()

  atexit()函數可以把一些函數注冊為退出函數(exit function)。函數原型如下:

int atexit(void (*func) (void))

  把函數指針傳遞給atexit()函數時,它會把指針保存起來留給將來引用。當程序將要正常終止時(或者由於調用exit,或者由於main函數返回),退出函數將被調用。退出函數不能接受任何參數

 

3 exit()

  exit()函數用於正常終止程序。函數原型如下:

void exit(int)

  如果程序以main函數返回一個值結束,那么其效果相當於用這個值作為參數調用exit()函數。在程序中的任何位置執行exit(n)調用通常等價於在main函數中執行return n。

  int參數返回給操作系統,用於提示程序是否正常完成。預定義符號EXIT_SUCCESSEXIT_FAILURE分別提示程序的終止成功還是失敗。exit()函數僅有的另一個可移植參數是0,它和宏EXIT_SUCCESS的意義相同。雖然程序也可以使用其他值,但它們的具體含義將取決於編譯器。

  當程序發現錯誤情況使它無法繼續執行下去時,這個函數尤其有用。你經常會在調用perrno之后再調用exit()終止程序。盡管終止程序並非處理所有錯誤的正確方法,但和一個注定失敗的程序繼續執行以后再失敗相比,這種做法更好一些。

  注意,這個函數沒有返回值。當exit()函數結束時,程序已經消失,所以它無處返回。

  當exit()函數被調用時,所有被atexit()函數注冊為退出函數的函數將按照它們所注冊的順序被反序依次調用(參數由於被壓入棧中,而先進后出)。然后,所有用於流的緩沖區被刷新,所有打開的文件被關閉。用tmpfile()函數創建的文件被刪除。然后,退出狀態返回給宿主環境,程序停止執行。

警告:

  由於程序停止執行,所以exit()函數絕對不會返回到它的調用處。但是,如果任何一個用atexit()注冊為退出函數的函數如果再次調用了exit(),其效果是未定義的。這個錯誤可能導致一個無限循環,很可能只有當堆棧的內存耗盡才會終止。

 

4 _exit()

  _exit()函數類似於exit()函數,但是_exit()不會調用atexit()注冊的退出函數,也不會調用之前傳遞給signal()函數的信號處理函數。此外,_exit()函數不需要清洗輸出緩沖區,關閉打開的流,以及刪除臨時文件,是否執行這些操作是由實現定義的。函數原型如下:

void _exit(int)

 

  按照ISO C規定,一個進程可以登記多達32個函數,通常這32個函數被稱為終止處理程序(退出函數),通過調用atexit()函數來登記這些函數,這些函數將由exit()函數自動調用。

  exit()和_exit()以及_Exit()函數的本質區別是是否立即進入內核,_exit()以及_Exit()函數都是在調用后立即進入內核,而不會執行一些清理處理,但是exit()則會執行一些清理處理,這也是為什么會存在atexit()函數的原因,因為exit()函數需要執行清理處理,需要執行一系列的操作,這些終止處理函數實際上就是完成各種所謂的清除操作的實際執行體。atexit函數的定義也給了程序員一種運用exit執行一些清除操作的方法,比如有一些程序需要額外的操作,具體的清除操作可以采用這種方法對特殊操作進行清除等。

  內核使程序執行的唯一方法是調用一個exec()函數,進程自願終止的唯一方法是顯式或者隱式調用(通過exit函數)_exit()或者_Exit()函數。因此exit函數中實質是對_exit()或者_Exit()函數的封裝。exit會先執行自定義的終止處理函數,然后執行I/O庫函數清理函數fclose(),這也是為什么可以在終止處理函數中可以繼續運用printf之類函數的原因,因為I/O庫函數的流對象還沒有被清除,當然可以繼續運用。執行完了所有的fclose()以后,可以執行真正意義上的終止函數_exit()或者_Exit()函數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM