1.main函數
C函數總是從執行一個名為main的函數開始。main函數的原型為
int main(int argc, char *argv[]);
其中 argc是命令列參數的數量而,argv是參數指標的數組。
2.進程終止
有8種方法終止一個進程。普通終止有5種:
1).從main函數中返回;
2).調用exit;
3).調用_exit或_Exit;
4).最後線程從啟動常式(eg:start函數)返回;
5).從最後線程裡調用pthread_exit
異常終止有3種:
6).調用abort
7).收到一個訊號
8).最後線程回應一個取消請求
Exit 函數
三個普通終止程式的函數:_exit和_Exit從核心立即返回;eixt則先執行特定清理處理然後從核心返回
#include <stdlib.h>void exit(int status);void _Exit(int status);#include <unistd.h>void _exit(int status);
atexit函數
根據ISO C,一個進程可以最多註冊32個函數,這些函數由exit函數調用的函數。這些被稱為exit處理器,並通過調用atexit函數來登記這些函數。
#include <stdlib.h>int atexit(void (*func)(void));//成功返回0,錯誤返回非0值。
聲明說我們傳遞一個函數地址作為atexit的參數。當這個函數被調用時,不傳入任何參數也不返回任何值。exit函數以它們註冊的順序的相反順序調用這些函數。每個函數都被調用和它被註冊的一樣多的次數。
3.命令列參數
當一個程式被執行時,使用exec的進程可以傳遞命令列參數給這個新的程式。這是UNIX系統shell的普通操作的一部分
4.環境表
每個程式還被傳入一個環境列表。就像參數列表那樣,環境列表是一個字元指標的數組,每個指標包含一個以null終止的C字串的地址。這個指標數組的地址包含在全域變數environ裡:
extern char **environ;
例如,如果環境由5個字串組成,用environ指向一個長度為5的指標數組。數組裡的每個地址都指向一個如“HOME=/home/tommy\0”形式的字串。每個字串的結尾處顯示的有null字元。我們稱environ為環境指標,稱指標數組為環境列表 ,稱它們指向的字串為環境字串
5.C程式的儲存空間布局
1).程式碼片段(text segment 又稱本文段),CPU執行的機器指令。通過,程式碼片段是可共用的,以便經常執行的程式只需在記憶體裡單個拷貝,比如文字編輯器,C編譯器,外殼,等等。還有程式碼片段通常是唯讀,為了阻止一個程式偶然修改了它的指令。
2).初始化的資料區段(Initialized data segment),通常簡稱為資料區段,包括在程式裡特別初始化的變數。例如,C出現在任何函數外的聲明int maxcount = 99;會導致這個變數以其初始值儲存在初始資料區段裡。
3).未初始化的資料區段(Uninitialized data segment),經常被稱為“bss”段,在代表“block started by symbol”的古老的彙編操作之後命令。在這個段的資料被核心在程式開始執行前初始化為數字0或null指標。出現在任何函數外的C聲明long sum[1000];導致這個變數被儲存在未初始化的資料區段裡。
4).棧,儲存自動變數和每次一個函數調用時儲存資訊的地方。每次一個函數被調用時,它要返回到的地址和關於調用者環境的特定資訊,比如一些機器寄存器,被儲存在棧裡。新調用的函數然後在棧上為自動和臨時變數開闢空間。這是在C裡的遞迴函式如何工作的。每次一個遞迴函式調用它自身時,一個新的棧架構被使用,所以一堆變數不會和這個函數的其它執行個體的變數衝突。
5).堆,動態記憶體分配通常發生的地方。曆史上,堆一直放在未初始化資料和棧之間。
這些段的典型布局是:最低地址是程式碼片段,其上是初始化資料,再上是未初始化資料,最高地址是命令列參數和環境變數,其下是棧,在棧和bss段之間是堆。
6.儲存空間分配
ISO C為記憶體配置規定了三個函數:
1).malloc:分配指定位元組數量的記憶體。記憶體的初始值是不確定的。
2).calloc:為指定數量的指定尺寸的對象開闢空間。這個空間被初始化為0。
3).realloc:增加或減少之前開闢的地區。當長度增加時,它可能會導致把之前開闢的空間移到其它地方,來在尾部提供額外的空間。還有,當長度增加時,在舊對空和新地區尾部之間的空間的初始值是不確定的。
#include <stdlib.h>void *malloc(size_t size);void *calloc(size_t nobj, size_t size);void *realloc(void *ptr, size_t newsize);//三者成功都返回非null 指標,錯誤返回NULL。void free(void *ptr);
7.環境變數
如同前述,環境字串的形式通常是這樣的格式:
name=value
1).ISO C定義了一個函數getenv,可以用其環境變數值,但是該標準又稱環境的內容是由實現定義的
#include <stdlib.h>char *getenv(const char *name);//返回和name相關的值的指標,沒有找到則返回NULL。
注意這個函數返回一個name=value的字串的指標。我們應該使用getenv來從環境得到指定的值,而不是直接存取environ。
2).
include <stdlib.h>int putenv(char *str);int setenv(const char *name, const char *value, int rewrite);int unsetenv(const char *name);//三者成功返回0,錯誤返回非0.
a.putenv函數取形式為name=value的字串,並把它放在環境列表中。如果name已經存在,它的舊的定義會首先被移除。
b.setenv將name設定為value,如果name存在於環境中,那麼1、如果rewrite為非0,則存在的name的定義首先被移除;2、如果rewrite為0,name的已存在的定義不被刪除,name不會被設定為新的value,也沒有錯誤發生。
c.unsetenv函數刪除任何name的定義。
注意putenv和setenv的區別。setenv必須開闢記憶體來建立它參數的name=value的字串,putenv可以把字串直接傳給環境。
8.setjmp和longjmp函數
setjmp 與 longjmp的結合使用,卻可以實現在不同程式之間的跳轉
#include <setjmp.h>int setjmp(jmp_buf env);//如果直接調用返回0,如果從longjmp調用返回則返回非0。void longjmp(jmp_buf env, int val);
我們從我們想回到的地點裡調用setjmp,在下面例子裡是main函數。這種情況下, setjmp返回0因為我們直接調用它。在這個setjmp的調用裡,env參數是一個特殊的類型jmp_buf。這個資料類型是某種格式的數組,能夠儲存所有所需的資訊,當我們調用longjmp時用來恢複棧的狀態。通常,env變數是一個全域變數,因為我們將需要從另一個函數裡引用它。
#include <setjmp.h>jmp_buf jmpbuffer;int main(void){ char line[MAXLINE]; if (setjmp(jmpbuffer) != 0) printf("error"); while (fgets(line, MAXLINE, stdin) != NULL) do_line(line); exit(0);}void cmd_add(void){ int token; token = get_token(); if (token < 0) longjmp(jmpbuffer, 1); /* rest of processing for this command */}/*當main被執行時,我們調用setjmp,它在變數jmpbuffer裡記錄任何它需要資訊並返回0。我們然後調用do_line,它會用 cmd_add,並假定察覺到某種形式的一個錯誤。
在cmd_add裡調用longjmp之前,棧裡有main、do_line和cmd_add函數的架構。但是longjmp導致棧直接回到main函數,把cmd_add和do_line的棧架構給丟棄了。調用
longjmp導致main裡的 setjmp返回,但這次它返回的值為1(longjmp的第二個參數。)*/
9.getrlimit和setrlimit函數
每個進程都有一堆資源限制,其中一些可以用getrlimit和setrlimit函數查詢和更改。
#include <sys/resource.h>int getrlimit(int resource, struct rlimit *rlptr);int setrlimit(int resource, const struct rlimit *rlptr);//兩者成功都返回0,錯誤都返回非0。
對於兩個函數的每次調用都指單個資源和一個指向以下結構體的指標:
struct rlimit { rlim_t rlim_cur; /* soft limit: current limit */ rlim_t rlim_max; /* hard limit: maximum value for rlim_cur */};