Linux系统调用之execve函数与标准C库exec函数族(有关于进程方面的函数族)
创始人
2025-05-29 01:51:51

前言

如果,想要深入的学习Linux系统调用里面的execve函数与标准C库中的exec函数族,还是需要去自己阅读Linux系统中的帮助文档。
具体输入命令:

man 2 execve
man 3 exec

即可查阅到完整的资料信息。

Linux系统调用之execve函数

在Linux系统调用中,execve()函数被用来加载并执行一个新的程序文件。其原型为:

int execve(const char *filename, char *const argv[], char *const envp[]);

它的三个参数分别为:

  • pathname:要被执行的可执行文件路径名。
  • argv:字符串数组指针,存放参数列表,最后一个元素必须是NULL。
  • envp:环境变量数组指针,用来设置新进程的环境变量,也同样以NULL结尾。
    该函数会用pathname指定的文件替换当前进程映像,从而执行pathname所指向的可执行程序,并将argv和envp作为参数传递给新程序。如果函数返回值为负数,则表示出错。

标准C库中的exec()函数族,都是源自于Linux系统调用中的execve()函数。其他exec()函数也基本上有着相同的功能,只不过使用的参数形式略有差异。

接下来让我们来介绍一下标准C库的exec函数族

标准C库exec函数族

在标准C库中,exec函数族是一组用于执行外部程序的系统调用。该函数族包括以下函数:

  • int execl(const char *path, const char *arg0, …, const char *argn, (char *) NULL); - 执行一个指定路径下的程序,并传递给它命令行参数列表。

  • int execv(const char *path, char *const argv[]); - 执行一个指定路径下的程序,并传递给它命令行参数列表。

  • int execle(const char *path, const char *arg0, …, const char *argn, (char *) NULL, char *const envp[]); - 执行一个指定路径下的程序,并传递给它命令行参数列表以及环境变量。

  • int execve(const char *path, char *const argv[], char *const envp[]); - 执行一个指定路径下的程序,并传递给它命令行参数列表以及环境变量。

  • int execlp(const char *file, const char *arg0, …, const char *argn, (char *) NULL); - 在当前的环境变量中查找指定的可执行文件,并运行它。

  • int execvp(const char *file, char *const argv[]); - 在当前的环境变量中查找指定的可执行文件,并运行它。

这些函数的返回值是:
如果成功,则不会返回;
如果失败,则返回 -1,并设置 errno 变量来表明错误类型。
这些exec函数族调用之后,操作系统会将其所属进程替换为新程序。如果新程序运行成功,那么整个进程就会被新程序所替代。

exec 函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。

exec 函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程 ID 等一些表面上的信息仍保持原样,颇有些神似“三十六计”中的“金蝉脱壳”。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回 -1,从原程序的调用点接着往下执行。

下面我们再具体介绍一下execl函数的参数与具体的代码示例

execl函数

execl() 是 exec() 函数族的一个成员,用于加载新程序并且使用一个参数列表来替换当前进程。以下是关于此函数的详细介绍:

函数原型

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

参数

path: 字符串类型的指针,指向需启动进程的路径,可以是相对路径或绝对路径。
arg: 指向传递给被执行程序的参数字符串。

返回值

如果成功,该函数不会返回,因为调用它后当前进程已经被替换了。如果出现错误,该进程将保持运行,并返回 -1。

功能和工作原理

execl() 函数从指定的文件路径加载新程序,并把当前进程替换成新的程序代码。传递的第二个参数是一个字符串常量,表示传递给新程序的命令行参数,一般是可执行程序的名称。注意,参数列表以 (char*)NULL 结尾。

当该函数调用成功时,控制权就被移交到新程序代码中,在新的进程环境下继续向下执行。新程序代码的主函数接收这些参数,并根据需要执行实际操作。

需要注意的是,新程序会完全替换当前进程,即包括该函数调用之前在内存中所执行过的过程都将被删除。如果任何资源(如打开的文件)没有进行正确的关闭,则可能会导致意外的行为。

代码示例:用execl函数替换子进程执行hello这个程序

//导入头文件
#include 
#include 
#include int main (){pid_t pid = fork();if(pid < 0){perror("fork");return -1;}if(pid > 0){printf("i am parent process,pid = %d\n",getpid());sleep(1);}else if(pid == 0){int ret = execl("hello","hello",NULL);if(ret == -1){perror("execl");return -1;}printf("i am child process,pid = %d\n",getpid());}for(int i = 0; i < 3; ++i){printf("i = %d, pid = %d\n",i,getpid());}return 0;
}

输出结果:

nowcoder@nowcoder:~/Linux/lession19$ ./execl 
i am parent process,pid = 13039
hello, world
i = 0, pid = 13039
i = 1, pid = 13039
i = 2, pid = 13039

execlp函数

execlp() 和 execl() 非常类似,不过它是根据 PATH 环境变量来查找目标二进制文件。这就意味着你可以只传递文件名而不需要整个路径。

以下是函数原型:

int execlp(const char *file, const char *arg0, ..., const char *argn, (char *) NULL)

具体使用方法请看代码:

#include 
#include int main() {// 创建一个子进程,在子进程中执行exec函数族中的函数pid_t pid = fork();if(pid > 0) {// 父进程printf("i am parent process, pid : %d\n",getpid());sleep(1);}else if(pid == 0) {// 子进程execlp("ls", "-l", NULL);printf("i am child process, pid : %d\n", getpid());}for(int i = 0; i < 3; i++) {printf("i = %d, pid = %d\n", i, getpid());}return 0;
}

输出内容:

nowcoder@nowcoder:~/Linux/lession19$ ./execlp
i am parent process, pid : 13354
execl  execl1.c  execl.c  execlp  execlp1.c  execlp.c  hello  hello.c
i = 0, pid = 13354
i = 1, pid = 13354
i = 2, pid = 13354

相关内容

热门资讯

省内外院校齐聚贵州民族大学,共...   12月27日,贵州民族大学举办“马院+书院”协同育人成果展暨“两个结合”赋能高校高质量发展学术研...
中非共和国举行大选 7名候选人... 来源:央视新闻客户端当地时间12月28日,中非共和国举行总统及国民议会选举。本次总统选举共有包括现任...
一组数据带你感受2025体育强... 经济观察网 据央视新闻客户端消息,记者近日从2025年全国体育局长会了解到,2025年我国运动员共在...
嘉美包装:如未来股票价格进一步... 每经AI快讯,12月28日,嘉美包装(002969.SZ)发布关于公司股票及可转债交易异常波动暨严重...