1. 程式人生 > >淺析exit()和atexit()函式

淺析exit()和atexit()函式

當核心使用一個一個exec函式執行c程式時,在呼叫main函式之前先呼叫一個特殊的啟動例程,可執行程式需將此例程指定為程式的起始地址。啟動例程從核心獲取命令列引數和環境變數,然後為呼叫mian函式做好準備。
exec函式說明:
fork函式是用於建立一個子程序,該子程序幾乎是父程序的副本,而有時我們希望子程序去執行另外的程式,exec函式族就提供了一個在程序中啟動另一個程式執行的方法。它可以根據指定的檔名或目錄名找到可執行檔案,並用它來取代原呼叫程序的資料段、程式碼段和堆疊段,在執行完之後,原呼叫程序的內容除了程序號外,其他全部被新程式的內容替換了。另外,這裡的可執行檔案既可以是二進位制檔案,也可以是Linux下任何可執行指令碼檔案。
那麼在linux中呼叫exec函式有兩種情況:
1)當程序認為自己不能再為系統和使用者做出任何貢獻時,就可以呼叫任何exec 函式族讓自己重生。
2)如果一個程序想執行另一個程式,那麼它就可以呼叫fork函式新建一個程序,然後呼叫任何一個exec函式使子程序重生。
程序終止:


程序種植的方式有8種,前5種為正常終止,後3種為異常終止:
1 從main函式返回
2 調⽤用exit函式;
3 調⽤用_exit或_Exit;
4 最後⼀一個執行緒從啟動例程返回;
5 最後⼀一個執行緒調⽤用pthread_exit;
6 調⽤用abort函式;
7 接到⼀一個訊號並終⽌止;
8 最後⼀一個執行緒對取消請求做出響應。
一般我們都是使用exit函式正常終止程序

#include <stdlib.h>
void exit( int status );
void _Exit( int status );
#include <unistd.h>
void _exit( int status );

_exit和_Exit立即進入核心,而exit要先做一些清理工作(呼叫執行個終止處理程式,關閉所有標準I/O流),再進入核心。三個函式所帶的整形引數稱為終止狀態或退出狀態,如果(a)呼叫這些函式不帶引數,(b)main函式中的return 語句無返回值,(c)main函式沒有宣告返回型別為整形,則程序的終止狀態是未定義的。main函式返回一個整形值與用該值呼叫exit是等價的。
注意:
exit函式執行時首先會執行由atexit()函式登記的函式,然後會做一些自身的清理工作,同時重新整理所有輸出流、關閉所有開啟的流並且關閉通過標準I/O函式tmpfile()建立的臨時檔案。
exit()函式用於在程式執行的過程中隨時結束程式,exit的引數state是返回給作業系統,返回0表示程式正常結束,非0表示程式非正常結束。
atexit函式:


atexit函式是一個特殊的函式,它是在正常程式退出時呼叫的函式,我們把他叫為登記函式
(函式原型:int atexit (void (*)(void)))

⼀一個程序可以登記若32個函式,這些函式由exit自動呼叫,這些函式被稱為終止處理函式,atexit函式可以登記這些函式。exit呼叫終止處理函式的順序和atexit登記的順序相反,如果一個函式被多次登記,也會被多次呼叫。

驗證atexit函式:
這裡寫圖片描述
執行結果為:
這裡寫圖片描述
先列印hello main睡眠五秒再依次列印test5,test4,test3,test2,test1(如果main函式中printf部分不加\n,則main函式要輸出的內容會先放到標準輸出緩衝區中,睡眠5秒後再打印出來,當main中呼叫exit函式的時候,會做一些自身清理工作,同時重新整理標準輸出緩衝區中的內容),當執行到exit(0)時,exit會自動呼叫已註冊過的函式,但是由於壓棧過程中先進後出的原則,所以先註冊的函式最後執行。如果一個函式被atexit()登記多次也會被exit()呼叫多次。