天天看點

exit( ),_exit( ),與return

C語言中的return,exit,break,continue。前兩個函數使用的同時通常都會帶上程式退出時的狀态碼,标準C中有EXIT_SUCCESS和EXIT_FAILURE兩個宏,位于/usr/include/stdlib.h中。

是這樣定義的的:

#define EXIT_FAILURE 1

#define EXIT_SUCCESS 0

exit函數的作用及其與_exit()函數的差別。

有庫檔案中的定義可知:exit是一個庫函數,exit(1)表示發生錯誤後退出程式,exit(0)表示正常退出。

在stdlib.h中exit函數是這樣子定義的:void exit(int status);

這個系統調用是用來終止一個程序的,無論在程式中的什麼位置,隻要執行exit,程序就會從終止程序的運作。

講到exit這個系統調用,就要提及另外一個系統調用,_exit,_exit()函數位于unistd.h中,相比于exit(),_exit()函數的功能最為簡單,直接終止程序的運作,釋放其所使用的記憶體空間,并銷毀在記憶體中的資料結構,而exit()在于在程序退出之前要檢查檔案的狀态,将檔案緩沖區中的内容寫回檔案。

下面我們通過于printf這個操作緩沖區的函數結合來說明上面的情況:

exit終止程序。

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

main()
{
printf("output begin\n");
exit(0);
printf("output end\n");
}
           

執行gcc -o exit1 exit1.c生成exit1,執行,隻會列印出output begin.

exit将緩沖區内容寫回檔案。

對應每一個打開的檔案,在記憶體中都有一片緩沖區,每次讀檔案時,會多讀出若幹條記錄,這樣下次讀檔案時就可以直接從記憶體的緩沖區中讀取,每次寫檔案的時候,也僅僅是寫入記憶體中的緩沖區,等滿足了一定的條件(達到一定數量,遇到特定字元(如換行符\n和檔案結束符EOF)),再将緩沖區中的内容一次性寫入檔案,我們知道

void exit(int status);

exit()用來正常終結目前程序的執行,并把參數status傳回給父程序,而程序所有的緩沖區資料會自動寫回并關閉未關閉的檔案。

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

main()
{
printf("output begin\n");
printf("content in buffer");
exit(0);
}
           

(gcc)

$ ./exit1

output begin

content in buffer

printf()會根據參數format字元串來轉換并格式化資料,然後将結果寫出到标準輸出裝置,直到出現字元串結束(’\0’)為止。可見,exit将未出現換行符的語句儲存到标注輸出檔案。

_exit()不會執行清理I/O緩沖的操作。

_exit()用來立刻結束目前程序的執行,并把參數status傳回給父程序,并關閉未關閉的檔案。此函數調用後不會傳回,并且會傳遞SIGCHLD信号給父程序,父程序可以由wait函數取得子程序結束狀态。

#include <stdio.h>
#include <unistd.h>

main()
{
printf("output begin\n");
printf("content in buffer\n");
_exit(0);
}
           

(gcc)

$ ./exit2

output begin

實際上因為第二條printf語句沒有滿足特定的條件,它們還隻是儲存在緩沖區内,這時我們用_exit()函數直接将程序關閉,緩沖區中的資料就會丢失,

和exit比較,return主要用于提供函數傳回值,continue,break語句則大多數情況下用于循環中。許多朋友可能會将這三條語句與exit搞混,并且對這三個語句區分不清楚。

return指令exit函數差別:

  • 形象地說,return是從A城市中的x小區到y小區,exit是直接走出A城
  • exit用于在程式運作的過程中随時結束程式,exit的參數是傳回給OS的。main函數結束時也會隐式地調用 exit函數。exit函數運作時首先會執行由atexit()函數登記的函數,然後會做一些自身的清理工作,同時重新整理所有輸出流、關閉所有打開的流并且關閉通過标準I/O函數tmpfile()建立的臨時檔案。exit是結束一個程序,它将删除程序使用的記憶體空間,同時把錯誤資訊傳回父程序。
    • exit可以傳回小于256的任何整數。傳回的不同數值主要是給調用者作不同處理的(單獨的程序是傳回給作業系統的。如果是多程序,是傳回給父程序的。父程序裡面調用waitpid()等函數得到子程序退出的狀态,以便作不同處理。根據相應的傳回值來讓調用者作出相應的處理.總的說來,exit()就是目前程序把控制權傳回給調用該程式的程式,括号裡的是傳回值,告訴調用程式該程式的運作狀态。)
    • exit(1)表示程序正常退出. 傳回 1;
    • exit(0)表示程序非正常退出. 傳回 0.
  • atexit()函數的參數是一個函數指針,函數指針指向一個沒有參數也沒有傳回值的函數。atexit()的函數原型是:int atexit (void (*)(void));在一個程式中最多可以用atexit()注冊32個處理函數,這些處理函數的調用順序與其注冊的順序相反,也即最先注冊的最後調用,最後注冊的最先調用
  • return是語言級别的,它表示了調用堆棧的傳回;而exit是系統調用級别的,它表示了一個程序的結束。return() 是目前函數傳回,當然如果是在主函數main, 自然也就結束目前程序了,如果不是,那就是退回上一層調用。在多個程序時.如果有時要檢測上程序是否正常退出的.就要用到上個程序的傳回值
  • 在有傳回值的函數中,return語句的作用是提供整個函數的傳回值,并結束目前函數傳回到調用它的地方。在沒有傳回值的函數中也可以使用return語句,例如當檢查到一個錯誤時提前結束目前函數的執行并傳回。一般程式執行到 main() 的結束就完成了, 如果想在程式結束時做一些事情, 可以嘗試着用這個函數.

    example:

#include <stdio.h>
void test1(void)
{
	printf("exit test1\n");
}

void test2(void)
{
	printf("exit test2\n");
}

int main()
{
	atexit(test1);
	atexit(test2);
	printf("exit main\n");
	return 0;
}
           

程序環境與程序控制(1): 程序的開始與終止

  1. 程序的開始:

C程式是從main函數開始執行, 原型如下:

int main(int argc, char *argv[]);

通常main的傳回值是int型, 正确傳回0.

如果main的傳回值為void或者無, 某些編譯器會給出警告, 此時main的傳回值通常是0.

關于main的指令行參數不做過多解釋, 以下面的程式展示一下:

以下是代碼片段:

  #include <stdio.h>
  int main(int argc, char *argv[]) 
  { 
  int i; 
  for (i = 0; i < argc; i++) 
  printf("argv[%d]: %s\n", i, argv[i]); 
  return 0; 
  }

           

2. 程序終止:

C程式的終止分為兩種: 正常終止和異常終止.

正常終止分為: return, exit, _exit, _Exit, pthreade_exit

異常中指分為: abort, SIGNAL, 線程響應取消

主要說一下正常終止的前4種, 即exit系列函數.

以下是代碼片段:

#include

  void exit(int status);

  void _Exit(int status);

  #include

  void _exit(int status);

以上3個函數的差別是:

exit()(或return 0)會調用終止處理程式和使用者空間的标準I/O清理程式(如fclose), _exit和_Exit不調用而直接由核心接管進行清

理.

是以, 在main函數中exit(0)等價于return 0.

3. atexit終止處理程式:

ISO C規定, 一個程序最對可登記32個終止處理函數, 這些函數由exit按登記相反的順序自動調用. 如果同一函數登記多次, 也會被

調用多次.

原型如下:

#include

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

其中參數是一個函數指針, 指向終止處理函數, 該函數無參無傳回值.

以下面的程式為例:

以下是代碼片段:

 #include <stdio.h>
  static void myexit1() 
  { 
  printf("first exit handler\n"); 
  } 
  static void myexit2() 
  { 
  printf("second exit handler\n"); 
  } 
  int main() 
  { 
  if (atexit(my_exit2) != 0) 
  printf("can't register my_exit2\n"); 
  if (atexit(my_exit1) != 0) 
  printf("can't register my_exit1\n"); 
  if (atexit(my_exit1) != 0) 
  printf("can't register my_exit1\n"); 
  printf("main is done\n"); 
  return 0; 
  }
           

運作結果: (gcc)

$./ a.out

main is done

first exit handler

first exit handler

second exit handler