專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

atexit函數(shù)和exit函數(shù)的理解

作者:huqin   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年03月13日   【字體:

  工作找完了,老板逼著寫各種亂七八糟的本子,偷著寫點(diǎn)自己的理解,就當(dāng)是對(duì)自己興趣愛(ài)好的補(bǔ)償吧。

   按照ISO C的規(guī)定,一個(gè)進(jìn)程可以登記多達(dá)32個(gè)函數(shù),這些函數(shù)將由exit自動(dòng)調(diào)用,通常這32個(gè)函數(shù)被稱為終止處理程序,并調(diào)用atexit函數(shù)來(lái)登記這些函數(shù)。

   我們通常認(rèn)為C語(yǔ)言的起始函數(shù)是main函數(shù),實(shí)質(zhì)上一個(gè)程序的啟動(dòng)函數(shù)并不一定是main函數(shù),這個(gè)可以采用鏈接器來(lái)設(shè)置,但是gcc中默認(rèn)main就是C語(yǔ)言的入口函數(shù),在main函數(shù)啟動(dòng)之前,內(nèi)核會(huì)調(diào)用一個(gè)特殊的啟動(dòng)例程,這個(gè)啟動(dòng)例程從內(nèi)核中取得命令行參數(shù)值和環(huán)境變量值,為調(diào)用main函數(shù)做好準(zhǔn)備,因此對(duì)應(yīng)程序而言main函數(shù)并不是起始,但是對(duì)應(yīng)C 語(yǔ)言而言,main函數(shù)就是入口地址,其他的鏈接器幫助我們完成,實(shí)際上mian函數(shù)的執(zhí)行是使用了exec函數(shù),這是一個(gè)函數(shù)族,這也是內(nèi)核執(zhí)行一個(gè)程序的唯一方法,這在進(jìn)程控制部分將進(jìn)行分析。
   
   記得在面試題中有一道關(guān)于在main函數(shù)退出之后,是否還可以執(zhí)行程序的問(wèn)題,這時(shí)候就要使用到前面提到的atexit函數(shù)。

     #include<stdlib.h>
     int atexit(void(*func)(void));

    其中,atexit的參數(shù)是一個(gè)函數(shù)地址,當(dāng)調(diào)用此函數(shù)時(shí)無(wú)須傳遞任何參數(shù),該函數(shù)也不能返回值,atexit函數(shù)稱為終止處理程序注冊(cè)程序,注冊(cè)完成以后,當(dāng)函數(shù)終止是exit()函數(shù)會(huì)主動(dòng)的調(diào)用前面注冊(cè)的各個(gè)函數(shù),但是exit函數(shù)調(diào)用這些函數(shù)的順序于這些函數(shù)登記的順序是相反的,我認(rèn)為這實(shí)質(zhì)上是參數(shù)壓棧造成的,參數(shù)由于壓棧順序而先入后出。同時(shí)如果一個(gè)函數(shù)被多次登記,那么該函數(shù)也將多次的執(zhí)行。
  
   我們知道exit是在main函數(shù)調(diào)用結(jié)束以后調(diào)用,因此這些函數(shù)的執(zhí)行肯定在main函數(shù)之后,這也是上面面試題的解決方法。即采用atexit函數(shù)登記相關(guān)的執(zhí)行函數(shù)即可。

   在exit函數(shù)的介紹中我們知道,exit()和_exit()以及_Exit()函數(shù)的本質(zhì)區(qū)別是是否立即進(jìn)入內(nèi)核,_exit()以及_Exit()函數(shù)都是在調(diào)用后立即進(jìn)入內(nèi)核,而不會(huì)執(zhí)行一些清理處理,但是exit()則會(huì)執(zhí)行一些清理處理,這也是為什么會(huì)存在atexit()函數(shù)的原因,因?yàn)閑xit()函數(shù)需要執(zhí)行清理處理,需要執(zhí)行一系列的操作,這些終止處理函數(shù)實(shí)際上就是完成各種所謂的清除操作的實(shí)際執(zhí)行體。atexit函數(shù)的定義也給了程序員一種運(yùn)用exit執(zhí)行一些清除操作的方法,比如有一些程序需要額外的操作,具體的清除操作可以采用這種方法對(duì)特殊操作進(jìn)行清除等。

    #include<stdio.h>
    #include<stdlib.h>

    void func1(void)
    {
            printf("in func1\n");
    }

    void func2(void)
    {
            printf("in func2\n");
    }

    void func3(void)
    {
            printf("in func3\n");
    }

    int main()
    {
            atexit(func3);
            atexit(func2);
            atexit(func1);

            printf("In main\n");

            return 0;
    }

   具體的執(zhí)行結(jié)果如下所示:

    [gong@Gong-Computer APUE]$ ./atexit
    In main
    in func1
    in func2
    in func3

   根據(jù)exit的執(zhí)行過(guò)此可知,exit首先會(huì)調(diào)用各個(gè)終止處理程序,然后按需多次調(diào)用fclose(),關(guān)閉所有打開(kāi)流,也就是說(shuō)exit函數(shù)會(huì)執(zhí)行一個(gè)標(biāo)準(zhǔn)I/O庫(kù)的清理關(guān)閉操作:對(duì)所有打開(kāi)的流調(diào)用fclose(),這樣就會(huì)造成所有緩沖的輸出數(shù)據(jù)都被沖洗即寫入文件中。

   內(nèi)核使程序執(zhí)行的唯一方法是調(diào)用一個(gè)exec函數(shù),進(jìn)程自愿終止哦的唯一方法是顯式或者隱式調(diào)用(通過(guò)exit函數(shù))_exit()或者_(dá)Exit()函數(shù)。因此exit函數(shù)中實(shí)質(zhì)是對(duì)_exit()或者_(dá)Exit()函數(shù)的封裝。exit會(huì)先執(zhí)行自定義的終止處理函數(shù),然后執(zhí)行I/O庫(kù)函數(shù)清理函數(shù)fclose(),這也是為什么可以在終止處理函數(shù)中可以繼續(xù)運(yùn)用printf之類函數(shù)的原因,因?yàn)镮/O庫(kù)函數(shù)的流對(duì)象還沒(méi)有被清除,當(dāng)然可以繼續(xù)運(yùn)用。執(zhí)行完了所有的fclose()以后,可以執(zhí)行真正意義上的終止函數(shù)_exit()或者_(dá)Exit()函數(shù)。

關(guān)閉窗口

相關(guān)文章