2016-02-02
命令行參數(shù)
當(dāng)執(zhí)行一個程序時鱼喉,調(diào)用exec的進(jìn)程可將命令行參數(shù)傳遞給該新程序。
其中argv[0]是 程序名稱
環(huán)境表
每個程序都接收一張環(huán)境表噩翠,與參數(shù)表一樣锈津,環(huán)境表也是一個字符指針數(shù)組暮顺,其中每個指針包含一個以null借宿的字符轉(zhuǎn)的地址乖篷。全局變量environ則包含了該指針數(shù)組的地址响驴。
extern char **environ
按照慣例環(huán)境由name=value這樣的字符串組成。大多數(shù)預(yù)定義名全由大寫字母組成撕蔼。通常用getenv和putenv函數(shù)來存取特定的環(huán)境變量豁鲤,而不是用environ變量,如果要查看整個環(huán)境則必須使用environ指針鲸沮。
c程序的存儲空間布局
由于歷史原因琳骡,c程序一直由下列幾部分組成
- 正文段。這是由CPU執(zhí)行的機器指令部分讼溺。通常正文段是可以共享的楣号。多以即使是經(jīng)常執(zhí)行的程序在存儲器中也只需有一個副本,另外正文段常常是只讀的怒坯。防止程序由于意外事故而修改其自身的指令炫狱。
- 初始化數(shù)據(jù)段。通常將此段成為數(shù)據(jù)段敬肚,它包含了程序中需要賦值的變量毕荐。例如c程序中任何函數(shù)之外的說明 int maxcount=99;使此變量以初值放在樹池花數(shù)據(jù)段中束析。
- 非初始化數(shù)據(jù)段艳馒。通常將此段成為bss,這一名稱來源于早期匯編程序的一個操作符员寇,在程序開始執(zhí)行之前弄慰,內(nèi)核程序?qū)⒋硕纬跏蓟癁?,函數(shù)外的說明 long sum[1000];將次變量存放在非初始化數(shù)據(jù)段中蝶锋。
- 棧陆爽。 自動變量及每次函數(shù)調(diào)用時所保存的信息都存放在此段中。每次函數(shù)調(diào)用時其返回地址扳缕,以及調(diào)用者的環(huán)境信息都存放在棧中慌闭。然后新被調(diào)用的函數(shù)在棧上為其自動和臨時變量分配儲存空間别威。通過以這種方式使用棧,c函數(shù)可以遞歸調(diào)用驴剔。
- 堆省古。同長在堆中進(jìn)行動態(tài)內(nèi)存分配。由于歷史上形成的慣例丧失,堆位于非初始化數(shù)據(jù)段頂和棧底之間
命令行參數(shù)和環(huán)境變量-->棧-->堆-->非初始化數(shù)據(jù)-->初始化數(shù)據(jù)-->正文
size命令報告正文段豺妓、數(shù)據(jù)段、bss段的長度
共享庫
現(xiàn)在很多unix系統(tǒng)支持共享庫布讹,共享庫是的可執(zhí)行程序文件中不再需要包含常用的庫函數(shù)琳拭,而只需在所有進(jìn)程都可存取的存儲區(qū)中保存這一種庫例程的一個副本。程序第一次執(zhí)行或則第一次調(diào)用某個庫函數(shù)時描验,用動態(tài)鏈接方法將程序與共享庫函數(shù)相連接白嘁。這就減少了每個可執(zhí)行文件的長度,但增加了一些運行時的開銷膘流。共享庫的另一個優(yōu)點是可以用庫函數(shù)的新版本代替老版本而無需對使用該庫的程序從新連接編輯权薯。
不同的系統(tǒng)使用不同的方法使說明程序是否要使用共享庫。比較典型的有cc和ls命令可選
存儲器分配
ANSI C說明了三個用于存儲空間動態(tài)分配的函數(shù)
- malloc分配指定字符數(shù)的存儲區(qū)睡扬。此存儲區(qū)中的初始值不確定盟蚣。
- calloc為指定長度的對象,分配能容納指定個數(shù)的存儲空間卖怜,該空間中的每一位都初始化為0
- realloc 更改以前分配去的長度屎开。當(dāng)增加長度時,可能需要將以前分配去的內(nèi)容移到另一個足夠大的區(qū)域马靠,而新增區(qū)域內(nèi)的初始值不確定奄抽。
void *malloc(size_t size);
void *calloc(sieze_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
void free(void *ptr);
這單個分配函數(shù)所犯規(guī)的指針一定是適當(dāng)對其的,使其可用于任何數(shù)據(jù)對象甩鳄。例如逞度,在一個特定的系統(tǒng)上,如果最苛刻的對其要求是double妙啃,則對其必須在8的倍數(shù)的地址單元處档泽,那么這三個函數(shù)返回的指針都應(yīng)這樣對齊。
realloc在改變存儲區(qū)大小的時候有可能會移動存儲區(qū)的位置揖赴,因此不應(yīng)當(dāng)使用任何指針指向此存儲區(qū)
realloc中若ptr為null則與malloc的功能相同馆匿。
這些分配例程通常調(diào)用sbrk系統(tǒng)調(diào)用實現(xiàn)。雖然sbrk可以擴從或者縮小一個進(jìn)程的存儲空間燥滑,但大多數(shù)malloc和free實現(xiàn)都不減小進(jìn)程的存儲空間渐北,釋放的空間可以供以后再分配,但他們被保存在malloc池而不返回給內(nèi)核铭拧。
應(yīng)當(dāng)注意的是大多數(shù)實現(xiàn)所分配的存儲空間比所要求的要稍微大一些赃蛛,額外的空間用來記錄管理信息分配塊的長度恃锉,指向下一個分配快的指針等。這就意味著如果寫過一個已分配區(qū)的尾端呕臂,則會改寫后一塊的管理信息淡喜。這種類型的錯誤是災(zāi)難性的。
其他的可能產(chǎn)生的致命性的錯誤是:釋放了一個已經(jīng)釋放的塊诵闭,調(diào)用free時所用的指針不是三個alloc函數(shù)返回值炼团。
因為存儲器分配出錯很難跟蹤,所以某些系統(tǒng)提供了這些函數(shù)的另外一種實現(xiàn)方法疏尿,每次調(diào)用者單個分配函數(shù)中的任意一個或者free時都進(jìn)行附加的出錯檢查瘟芝。
alloca函數(shù)
其調(diào)用序列與malloc相同,但是它是在當(dāng)前函數(shù)的棧幀上分配存儲空間褥琐,而不是在堆中锌俱。其優(yōu)點是:當(dāng)函數(shù)返回時,自動釋放它所使用的棧幀敌呈,多以不必再為釋放空間而費心贸宏。其缺點是:某些系統(tǒng)在函數(shù)一杯調(diào)用后不能增加棧幀的長度,于是也就不能支持alloca函數(shù)磕洪。
環(huán)境變量
如同前面所述吭练,環(huán)境字符串的形式是:name=value
unix內(nèi)核并不關(guān)心這種字符串的意義,他的解釋完全取決于各個應(yīng)用程序析显。
char *getenv(const char *name)
除了取環(huán)境變量鲫咽,有時也需要設(shè)置環(huán)境變量,或者改變現(xiàn)有的變量的值谷异,或者是增加新變量的(我們能影響的是當(dāng)前進(jìn)程及其后生成的子進(jìn)程的環(huán)境分尸,但不能影響父進(jìn)程的環(huán)境)
int putenv(const char *str)
int setenv(const char *name, const char *value, int rewrite)
void unsetenv(const char *name)
setjmp和longjmp
在C中不允許使用跳躍函數(shù)goto 而執(zhí)行這種跳轉(zhuǎn)功能的是函數(shù)setjmp和longjmp這兩個函數(shù)對于處理發(fā)生在很深的嵌套函數(shù)調(diào)用中出錯情況非常有用。
int setjmp(jmp_buf env)
void longjmp(jmp_buf env, int val)
在希望返回到達(dá)的位置調(diào)用setjmp歹嘹。setjmp的參數(shù)env是一個特殊類型jmp_buf這一數(shù)據(jù)類型是某種形式的數(shù)組箩绍,其中UC南方在調(diào)用longjmp時能用來恢復(fù)棧狀態(tài)的所有信息。一般尺上,env變量是個全局變量材蛛,因為需要從另一個函數(shù)中引用它。
當(dāng)檢查到一個錯誤時尖昏,則以兩個參數(shù)滴啊用longjmp第一個就是在調(diào)用setjmp時所用的env第二個val是個非0值仰税,它成為setjmp處返回的值。使用第二個參數(shù)的原因是對于一個setjmp可以有多個longjmp抽诉。
自動、寄存器和易失變量
當(dāng)longjmp返回時吐绵,大多數(shù)實現(xiàn)并不回滾自動變量和寄存器變量迹淌。如果你有一個自動變量而又不想使其值回滾河绽,則可以定義其為具有volatile屬性。說明為全局和靜態(tài)變量的值在執(zhí)行l(wèi)ongjmp時保持不變唉窃。因此如果要編寫一個使用非局部跳轉(zhuǎn)的可移植程序耙饰,則必須使用volatile屬性。
自動變量的潛在問題
基本規(guī)則是說明自動變量的函數(shù)已經(jīng)返回后纹份,就不能再引用這些自動變量苟跪。
getrlinit和setrlimit函數(shù)
每個進(jìn)程都有一組資源限制,其中某一些可以用getrlimit和setrlimit函數(shù)查詢和更改
int getrlimit(int resource, struct rlinit *rlptr)
int setrlinit(int resource, const struct rlimit *rlptr)
對這兩個函數(shù)的每一次調(diào)用都制定一個資源以及一個指向下列結(jié)構(gòu)的指針
struct rlimit {
rlimi_t rlim_cur;
rlimi_t rlim_max;
}
進(jìn)程的資源限制通常是在系統(tǒng)初始化時由0進(jìn)程建立的蔓涧,然后由后續(xù)進(jìn)程繼承件已。
更改資源限制時,需準(zhǔn)守下列三條原則:
- 任何一進(jìn)程都可將一個軟限制更改為小于等于其硬件限制
- 任何一個進(jìn)程都可降低其銀監(jiān)限制值元暴,但它必須大于等于其軟件限制值篷扩。這種降低對于普通用戶而言是不可逆反的。
- 只有超級用戶可以提高硬件限制
資源限制影響到調(diào)用進(jìn)程并由其子進(jìn)程繼承茉盏。