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): 程序的開始與終止
- 程序的開始:
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