exec函式家族總結

2021-07-02 03:38:45 字數 4623 閱讀 5108

exec函式族的作用是根據指定的檔名找到可執行檔案,並用它來取代呼叫程序的內容,換句話說,就是在呼叫程序內部執行乙個可執行檔案。這裡的可執行檔案既可以是二進位制檔案,也可以是任何linux下可執行的指令碼檔案。與一般情況不同,exec函式族的函式執行成功後不會返回,因為呼叫程序的實體,包括**段,資料段和堆疊等都已經被新的內容取代,只留下程序id等一些表面上的資訊仍保持原樣,頗有些神似"三十

六計"中的"金蟬脫殼"。看上去還是舊的軀殼,卻已經注入了新的靈魂。只有呼叫失敗了,

它們才會返回乙個-1,從原程式的呼叫點接著往下執行。

1.exec家族一共有六個函式,分別是:

(1)int execl(const char *path, const char *arg, ......);

(2)int execle(const char *path, const char *arg, ...... , char * const envp);

(3)int execv(const char *path, char *const argv);

(4)int execve(const char *path, char *const argv, char *const envp);

(5)int execvp(const char *filename, char * const argv);

(6)int execlp(const char *filename, const char *arg, ......);

其中只有execve是真正意義上的系統呼叫,其它都是在此基礎上經過包裝的庫函式。

" l "代表 list即 列表,對應可變引數argv 以列表的形式出現

" v "代表 vector即向量陣列,對應可變引數argv以陣列的形式出現

" e " 代表 environment ,對應 envp陣列,是指給可執行檔案指定環境變數。在全部6個函式中,只有execle和execve使用了char *envp傳遞環境變數,其它的4個函式都沒有這個引數,這並不意味著它們不傳遞環境變數,這4個函式將把預設的環境變數不做任何修改地傳給被執行的應用程式。而execle和execve用指定的環境變數去替代預設的那些。

" p " 代表 環境變數path ,字母p是指在環境變數path的目錄裡去查詢要執行的可執行檔案.2個以p結尾的函式execlp和execvp,看起來,和execl與execv的差別很小,事實也如此,它們的區別從第乙個引數名可以看出:除 execlp和execvp之外的4個函式都要求,它們的第1個引數path必須是乙個完整的路徑,如"/bin/ls";而execlp和execvp 的第1個引數file可以僅僅只是乙個檔名,如"ls",這兩個函式可以自動到環境變數path指定的目錄裡去查詢。

2.它們之間的區別:

第乙個區別是:

前四個取路徑名做為引數,後兩個取檔名做為引數,如果檔名中不包含 「/」 則從path環境變數中搜尋可執行檔案, 如果找到了乙個可執行檔案,但是該檔案不是連線編輯程式產生的可執行**檔案,則當做shell指令碼處理。

第二個區別:

前兩個和最後乙個函式中都包括「 l 」這個字母 ,而另三個都包括「 v 」。" v "代表 vector即是以"char *argv"(vector)形式傳遞命令列引數,陣列的最後乙個元素為null。" l "代表 list,即前三個函式的引數都是以list的形式給出的,但最後引數為null(如果用常數0來表示空指標,則必須將它強行轉換成字元指標,否則有可能出錯)。

最後乙個區別:

與向新程式傳遞環境變數有關,如第二個和第四個以e結尾的函式,可以向函式傳遞乙個指向環境字串指標陣列的指標。即自個定義各個環境變數,而其它四個則使用程序中的環境變數。

返回值與一般情況不同,exec函式族的函式執行成功後不會返回,因為呼叫程序的實體,包括**段,資料段和堆疊等都已經被新的內容取代,只有程序id等一些表面上的資訊仍保持原樣。呼叫失敗時,會設定errno並返回-1,然後從原程式的呼叫點接著往下執行。

與其他系統呼叫比起來,exec很容易失敗,被執行檔案的位置,許可權等很多因素都能導致呼叫失敗。因此,使用exec函式族時,一定要加錯誤判斷語句。最常見的錯誤:

找不到檔案或路徑,此時errno被設定為enoent;

陣列argv和envp忘記用null結束,此時errno被設定為efault;

沒有對要執行檔案的執行許可權,此時errno被設定為eacces。

3.例項講解:

(1)在平時的程式設計中,如果用到了exec函式族,一定記得要加錯誤判斷語句。先判斷execl的返回值,如果出錯,可以用perror( )函式列印出錯誤資訊。

如:if (execl(「path」,」..」」(char *)0) < 0)

perror(「execl error!」);

如果呼叫出錯,可輸出:execl error!: 錯誤原因   這樣可方便查詢出錯原因

(2)注意下面書寫格式:

先定義乙個指標陣列:char *argv=

用execv呼叫ls:    execv(「/bin/ls」,argv)

如果用execvp

execvp(「ls」,argv)      //直接寫ls就可以了

注意:execl呼叫shell 時,要在shell指令碼中指明使用的shell版本:#!/bin/bash。在命令列下執行shell指令碼,系統為它自動開啟乙個shell,在程式中沒有shell,在呼叫shell指令碼時,會出錯,所以要在shell指令碼中先開啟shell。

2、應用

如果乙個程序想執行另乙個程式,它就可以fork或vfork出乙個新程序,然後呼叫任何乙個exec函式。

為此,linux還專門對fork作了優化:通常fork會將呼叫程序的所有內容原封不動的拷貝到新產生的子程序中去,這些拷貝的動作很消耗時 間,而如果fork完之後我們馬上就呼叫exec,那這些辛辛苦苦拷貝來的東西就會被立刻抹掉,這看起來非常不划算,於是人們設計了一種"寫時複製(copy-on-write)" 技術,使得fork結束後並不立刻複製父程序的內容到子程序,而是到了真正使用時才複製,這樣如果下一條語句是exec,它就不會作無用功了。其實"寫時 複製"還是有複製,程序的mm結構、頁表都還是被複製了("寫時複製"也必須由這些資訊來支撐。否則核心捕捉到cpu訪存異常,怎麼區分 這是「寫時複製」引起的,還是真正的越權訪問呢?)。

而vfork就把事情做絕了,所有有關於記憶體的東西都不複製了,父子程序的記憶體是完全共享的。但是這樣一來又有問題了,雖然使用者程式可以設計很多方法來避免父子程序間的訪存衝突。但是關鍵的一點,父子程序共用著棧,這可不由使用者程式控制的。乙個進 程進行了關於函式呼叫或返回的操作,則另乙個程序的呼叫棧 (實際上就是同乙個棧)也被影響了。這樣的程式沒法執行下去。所以,vfork有個限制,子程序生成後,父程序在vfork中被核心掛起,直到子程序有了 自己的記憶體空間(exec**)或退出(_exit)。並且, 在此之前,子程序不能從呼叫vfork的函式中返回(同時,不能修改棧上變數、不能繼續呼叫除_exit或exec系列之外的函式,否則父程序的資料可能 被改寫)。

儘管限制很多,vfork後馬上exec效率會比fork高不少。

/* exec.c */

#include main()

; char *argv_execv=;

char *argv_execvp=;

char *argv_execve=;

if(fork()==0)

if(execl("/bin/echo", "echo", "executed by execl", null)<0)

perror("err on execl");

if(fork()==0)

if(execlp("echo", "echo", "executed by execlp", null)<0)

perror("err on execlp");

if(fork()==0)

if(execle("/usr/bin/env", "env", null, envp)<0)

perror("err on execle");

if(fork()==0)

if(execv("/bin/echo", argv_execv)<0)

perror("err on execv");

if(fork()==0)

if(execvp("echo", argv_execvp)<0)

perror("err on execvp");

if(fork()==0)

if(execve("/usr/bin/env", argv_execve, envp)<0)

perror("err on execve");

}

由於各個子程序執行的順序無法控制,所以有可能出現乙個比較混亂的輸出--各子程序列印的結果交雜在一起,而不是嚴格按照程式中列出的次序。若將程式中fork都改為vfork,則各個exec執行的程式將按序執行。

exec族函式總結

1 execve為系統呼叫 其他的都是封裝的函式 l 引數列表 p 在環境變數path中尋找 v 引數陣列 e 替換環境變數列表 返回值 函式出錯 返回0 否則不反回 原來的使用者區已經被替換 只留下pcb所以沒有返回的地方 exec族函式只替換使用者區 但是對核心區的pcb也有一定的影響 詳見 a...

linux中程序執行exec家族

啟動程序 exec族 共用標頭檔案 include int execl const char path,const char arg,int execlp const char file,const char arg,int execle const char path,const char arg...

linux exec函式家族

1.exec家族一共有六個函式,分別是 1 int execl const char path,const char arg,2 int execle const char path,const char arg,char const envp 3 int execv const char path...