(1)exec函式說明
fork函式是用於建立乙個子程序,該子程序幾乎是父程序的副本,而有時我們希望子程序去執行另外的程式,exec函式族就提供了乙個在程序中啟動另乙個程式執行的方法。它可以根據指定的檔名或目錄名找到可執行檔案,並用它來取代原呼叫程序的資料段、**段和堆疊段,在執行完之後,原呼叫程序的內容除了程序號外,其他全部被新程式的內容替換了。另外,這裡的可執行檔案既可以是二進位制檔案,也可以是linux下任何可執行指令碼檔案。
(2)在linux中使用exec函式族主要有以下兩種情況
a. 當程序認為自己不能再為系統和使用者做出任何貢獻時,就可以呼叫任何exec 函式族讓自己重生。
b. 如果乙個程序想執行另乙個程式,那麼它就可以呼叫fork函式新建乙個程序,然後呼叫任何乙個exec函式使子程序重生。
(3)exec函式族語法
實際上,在linux中並沒有exec函式,而是有6個以exec開頭的函式族,下表列舉了exec函式族的6個成員函式的語法。
所需標頭檔案: #include
函式說明: 執行檔案
函式原型:
[plain]view plain
copy
int execl(const char *path, const char *arg, ...)
int execv(const char *path, char *const argv)
int execle(const char *path, const char *arg, ..., char *const envp)
int execve(const char *path, char *const argv, char *const envp)
int execlp(const char *file, const char *arg, ...)
int execvp(const char *file, char *const argv)
函式返回值:成功 -> 函式不會返回,出錯 -> 返回-1,失敗原因記錄在error中。
這6 個函式在函式名和使用語法的規則上都有細微的區別,下面就可執行檔案查詢方式、參數列傳遞方式及環境變數這幾個方面進行比較說明。
① 查詢方式:上表其中前4個函式的查詢方式都是完整的檔案目錄路徑,而最後2個函式(也就是以p結尾的兩個函式)可以只給出檔名,系統就會自動從環境變數「$path」所指出的路徑中進行查詢。
② 引數傳遞方式:exec函式族的引數傳遞有兩種方式,一種是逐個列舉的方式,而另一種則是將所有引數整體構造成指標陣列進行傳遞。
在這裡引數傳遞方式是以函式名的第5位字母來區分的,字母為「l」(list)的表示逐個列舉的方式,字母為「v」(vertor)的表示將所有引數整體構造成指標陣列傳遞,然後將該陣列的首位址當做引數傳給它,陣列中的最後乙個指標要求是null。讀者可以觀察execl、execle、execlp的語法與execv、execve、execvp的區別。
③ 環境變數:exec函式族使用了系統預設的環境變數,也可以傳入指定的環境變數。這裡以「e」(environment)結尾的兩個函式execle、execve就可以在envp中指定當前程序所使用的環境變數替換掉該程序繼承的所以環境變數。
(4)path環境變數說明
path環境變數包含了一張目錄表,系統通過path環境變數定義的路徑搜尋執行碼,path環境變數定義時目錄之間需用用「:」分隔,以「.」號表示結束。path環境變數定義在使用者的.profile或.bash_profile中,下面是path環境變數定義的樣例,此path變數指定在「/bin」、「/usr/bin」和當前目錄三個目錄進行搜尋執行碼。
path=/bin:/usr/bin:.
export $path
(5)程序中的環境變數說明
在linux中,shell程序是所有執行碼的父程序。當乙個執行碼執行時,shell程序會fork子程序然後呼叫exec函式去執行執行碼。shell程序堆疊中存放著該使用者下的所有環境變數,使用execl、execv、execlp、execvp函式使執行碼重生時,shell程序會將所有環境變數複製給生成的新程序;而使用execle、execve時新程序不繼承任何shell程序的環境變數,而由envp陣列自行設定環境變數。
(6)exec函式族關係
第4位統一為:exec
第5位l:引數傳遞為逐個列舉方式
execl、execle、execlp
v:引數傳遞為構造指標陣列方式
execv、execve、execvp
第6位e:可傳遞新程序環境變數
execle、execve
p:可執行檔案查詢方式為檔名
execlp、execvp
事實上,這6個函式中真正的系統呼叫只有execve,其他5個都是庫函式,它們最終都會呼叫execve這個系統呼叫,呼叫關係如下圖12-11所示:
圖12-11 exec函式族關係圖
(7)exec呼叫舉例如下:
[plain]view plain
copy
char *const ps_argv =;
char *const ps_envp =;
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", null);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", null, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", null);
execvp("ps", ps_argv);
請注意exec函式族形參展開時的前兩個引數,第乙個引數是帶路徑的執行碼(execlp、execvp函式第乙個引數是無路徑的,系統會根據path自動查詢然後合成帶路徑的執行碼),第二個是不帶路徑的執行碼,執行碼可以是二進位制執行碼和shell指令碼。
(8)exec函式族使用注意點
在使用exec函式族時,一定要加上錯誤判斷語句。因為exec很容易執行失敗,其中最常見的原因有:
① 找不到檔案或路徑,此時errno被設定為enoent。
② 陣列argv和envp忘記用null結束,此時errno被設定為efault。
③ 沒有對應可執行檔案的執行許可權,此時errno被設定為eacces。
(9)exec後新程序保持原程序以下特徵
ÿ 環境變數(使用了execle、execve函式則不繼承環境變數);
ÿ 程序id和父程序id;
ÿ 實際使用者id和實際組id;
ÿ 附加組id;
ÿ 程序組id;
ÿ 會話id;
ÿ 控制終端;
ÿ 當前工作目錄;
ÿ 根目錄;
ÿ 檔案許可權遮蔽字;
ÿ 檔案鎖;
ÿ 程序訊號遮蔽;
ÿ 未決訊號;
ÿ 資源限制;
ÿ tms_utime、tms_stime、tms_cutime以及tms_ustime值。
對開啟檔案的處理與每個描述符的exec關閉標誌值有關,程序中每個檔案描述符有乙個exec關閉標誌(fd_cloexec),若此標誌設定,則在執行exec時關閉該描述符,否則該描述符仍開啟。除非特地用fcntl設定了該標誌,否則系統的預設操作是在exec後仍保持這種描述符開啟,利用這一點可以實現i/o重定向。
(10)execlp函式舉例
execlp.c源**如下:
[plain]view plain
copy
#include
#include
int main()
} return 0 ;
}
編譯 gcc execlp.c –o execlp。
執行 ./execlp,執行結果如下:
[plain]view plain
copy
home=/home/test
db2db=test
shell=/bin/bash
……
由執行結果看出,execlp函式使執行碼重生時繼承了shell程序的所有環境變數,其他三個不以e結尾的函式同理。
(11)execle函式舉例
利用函式execle,將環境變數新增到新建的子程序中去。
execle.c源**如下:
[plain]view plain
copy
#include
#include
int main()
; if(fork()==0)
} return 0 ;
}
編譯:gcc execle.c –o execle。執行./execle,執行結果如下:
[plain]view plain
copy
path=/tmp
user=sun
可見,使用execle和execve可以自己向執行程序傳遞環境變數,但不會繼承shell程序的環境變數,而其他四個exec函式則繼承shell程序的所有環境變數。
巨集函式及其用法
1 在乙個預處理器巨集中的引數前面使用乙個 預處理器會把這個引數轉換為乙個字元陣列,如 define p a printf s d a,a int a 1,b 2 p a b 則會輸出 a b 3 2 是一種分割連線方式,它的作用是先分割,然後進行強制連線。例如 define a1 name,typ...
Oracle decode 函式及其用法
decode 函式,它將輸入數值與函式中的引數列表相比較,根據輸入值返回乙個對應值。函式的引數列表是由若干數值及其對應結果值組成的若干序偶形式。當然,如果未能與任何乙個實參序偶匹配成功,則函式也有預設的返回值。語法結構如下 decode expression,search 1,result 1 de...
memset函式及其用法
每種型別的變數都有各自的初始化方法,memset 函式可以說是初始化記憶體的 萬能函式 通常為新申請的記憶體進行初始化工作。它是直接操作記憶體空間,mem即 記憶體 memory 的意思。該函式的原型為 include void memset void s,int c,unsigned long n...