liunx中exec函式組

2021-06-22 09:05:39 字數 3710 閱讀 3617

1、簡介

在linux中,並不存在exec()函式,exec指的是一組函式,一共有6個,分別是:

#include

extern char **environ;

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

int execlp(const char *file, const char *arg, ...);

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

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

int execvp(const char *file, char *const argv);

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

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

exec函式族的作用是根據指定的檔名找到可執行檔案,並用它來取代呼叫程序的內容

,換句話說,就是在呼叫程序內部執行乙個可執行檔案

。這裡的可執行檔案既可以是二進位制檔案

,也可以是任何linux下可執行的指令碼檔案。

函式名與引數的關係:

細看一下,這6個函式都是以exec開頭(表示屬於exec函式組),前3個函式接著字母l的,後3個接著字母v的,我的理解是l表示list(列舉引數),v表示vector(引數向量表)

。它們的區別在於,execv開頭的函式是以"char *argv"(vector)形式傳遞命令列引數,而execl開頭的函式採用了羅列(list)的方式,把引數乙個乙個列出來,然後以乙個null表示結束。這裡的null的作用和argv陣列裡的null作用是一樣的。

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

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

返回值

與一般情況不同,exec函式族的函式執行成功後不會返回

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

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

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

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

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

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 

*/unistdh #include

<

.>

main

void

(void);

argv_execv

char*

=;argv_execvp

char*

=;argv_execve

char*

=;fork 0if

(()==

)execl 0if

(("/bin/echo",

"echo",

"executed by execl

",null)

<

)perror(

"err on execl");

fork 0if

(()==

)execlp 0if

(("echo",

"echo",

"executed by execlp

",null)

<

)perror(

"err on execlp");

fork 0if

(()==

)execle envp 0if

(("/usr/bin/env",

"env

",null,)

<

)perror(

"err on execle");

fork 0if

(()==

)execv argv_execv 0if

(("/bin/echo",)

<

)perror(

"err on execv");

fork 0if

(()==

)execvp argv_execvp 0if

(("echo",)

<

)perror(

"err on execvp");

fork 0if

(()==

)execve argv_execve envp 0if

(("/usr/bin/env

",,)

<

)perror(

"err on execve");

}

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

exec函式組的用法

exec函式組 在fork後的子程序中使用exec函式族,可以裝入和執行其它程式 子程序替換原有程序,和父程序做不同的事 fork建立乙個新的程序就產生了乙個新的pid,exec啟動乙個新程式,替換原有的程序,因此這個新的被 exec 執行的程序的pid不會改變 和呼叫exec的程序的pid一樣 在...

Linux中exec族函式詳解

1 exec函式說明 fork函式是用於建立乙個子程序,該子程序幾乎是父程序的副本,而有時我們希望子程序去執行另外的程式,exec函式族就提供了乙個在程序中啟動另乙個程式執行的方法。它可以根據指定的檔名或目錄名找到可執行檔案,並用它來取代原呼叫程序的資料段 段和堆疊段,在執行完之後,原呼叫程序的內容...

Linux中的exec函式族

fork 建立子程序後執行的是和父程序相同的程式 但有可能執行不同的 分支 子程序往往要呼叫一種 exec 函式以執行另乙個程式。當程序呼叫一種 exec 函式時,該程序的使用者空間 和資料完全被新程式替換,從新程式的啟動例程開始執行。呼叫 exec 並不建立新程序,所以呼叫 exec 前後該程序的...