Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學

Linux execl 系列函數詳解與進程替換機制實戰

編輯:Linux 系統常見問題解答

函數族原型


#include 

int execl(const char *path, const char *arg0, ..., (char *)NULL);
int execlp(const char *file, const char *arg0, ..., (char *)NULL);
int execle(const char *path, const char *arg0, ..., (char *)NULL, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);  // 系統調用入口

後綴含義速記

  • l - list (參數列表,以 NULL 結尾)
  • v - vector (參數數組 argv[])
  • p - path (搜索 PATH 環境變量)
  • e - environment (指定環境變量數組 envp[])

核心機制:進程替換

  • 調用 exec 族函數不創建新進程,PID 不變。
  • 當前進程的 正文、數據、堆、棧段完全被新程序替換。
  • 只有 進程 ID、父進程 ID、文件描述符表 (除 FD_CLOEXEC)、信號屏蔽集、當前工作目錄、用戶/組 ID 等少數屬性保留。
  • exec 成功不返回,新程序從 main() 開始執行;失敗返回 -1 (errno 指示錯誤),原程序繼續執行。

實戰示例 1:execl 執行 ls


#include 
#include 

int main() {
    printf("Before execl, PID=%d\n", getpid());
    // execl(path, arg0, arg1, ..., NULL)
    // arg0 習慣為程序名,實際由 argv[0] 接收
    if (execl("/bin/ls", "ls", "-l", "/etc/passwd", (char *)NULL) < 0) {
        perror("execl failed");
    }
    // 此行僅在 execl 失敗時執行
    printf("This line only prints if execl fails\n");
    return 0;
}

輸出:直接顯示 ls -l /etc/passwd 結果,無 "This line..." 輸出,證明進程已被替換。

實戰示例 2:父進程調用子程序創建文件


// file_creat.c (被調用程序)
#include 
#include 
#include 

void create_file(char *filename) {
    if (creat(filename, 0666) < 0) {
        perror("create file failed");
        exit(EXIT_FAILURE);
    }
    printf("File %s created successfully\n", filename);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s \n", argv[0]);
        exit(EXIT_FAILURE);
    }
    create_file(argv[1]);
    return 0;
}

// execl_test.c (主程序)
#include 
#include 
#include 

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s \n", argv[0]);
        exit(EXIT_FAILURE);
    }
    // 執行 ./file_creat filename
    if (execl("./file_creat", "file_creat", argv[1], (char *)NULL) < 0) {
        perror("execl error");
    }
    return 0;
}

編譯運行:


gcc file_creat.c -o file_creat
gcc execl_test.c -o execl_test
./execl_test testfile.txt
# 輸出: File testfile.txt created successfully

常見錯誤與最佳實踐

錯誤後果修正
參數列表未以 NULL 結尾棧溢出、未定義行為務必以 (char *)NULL 結尾
arg0 與程序名不一致程序內 argv[0] 顯示異常,影響日志/用法提示arg0 設為程序名 (不含路徑)
execl 後有代碼預期執行邏輯錯誤,exec 成功不返回需 fork() 創建子進程再 exec,父進程 wait()
環境變量未傳遞 (execle/execvpe)子進程環境異常顯式構造 envp[] 或使用 execvp 繼承當前 environ

fork + exec 模式 (標準創建子進程執行新程序)


pid_t pid = fork();
if (pid < 0) { perror("fork"); exit(1); }
if (pid == 0) {  // 子進程
    execlp("myprogram", "myprogram", "arg1", "arg2", (char *)NULL);
    perror("execlp failed");  // 僅執行失敗時到達
    _exit(127);               // 子進程異常退出碼
} else {         // 父進程
    int status;
    waitpid(pid, &status, 0);
    if (WIFEXITED(status))
        printf("Child exited with %d\n", WEXITSTATUS(status));
}
Copyright © Windows教程網 All Rights Reserved