本文目录
一、exec函数簇介绍
exec 函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。
exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容(也就是新的进程信息会替换原进程的"用户区"的信息)取代,只留下进程ID等一些表面上的信息仍保持原样(比如PID、PPID、进程组号等这些在内核区的PCB中的信息),颇有些神似"三十六计"中的"金蝉脱壳"。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回-1,从原程序的调用点接着往下执行。
二、exec函数簇
cpp
int execl(const char *path,const char *arg,.../* (char *) NULL */);
int execlp(const char *file,const char *arg,.../* (char *) NULL */);
int execle(const char *path,const char *arg,.../* (char *) NULL ,char * const envp[] */;
int execv(const char *path,char *const argv[]);
int execvp(const char *file ,char *const argv[]);
int execvp(const char *file,char *const argv[], char *const envp[]);
//前面几个都是标准c库的函数,下面这个是linux的函数,一般来说就最上面两个用的最多。
int execve(const char *filename,char *const argv[],char *const envp[]);
l:list
参数地址列表,以空指针结尾。
v:vector
存有各参数地址的指针数组的地址。
p:path
按PATH环境变量指定的目录搜索可执行文件。
e:environment
存有环境变量字符串地址的指针数组地址。
输入man 3 exec
查看标准C库的文档解释:
首先在某个文件夹下创建hello.c文件,代码如下:
cpp
#include <stdio.h>
int main() {
printf("hello, world\n");
return 0;
}
然后在同级文件夹下创建execl.c文件,然后通过gcc exec.c -o exec
进行编译。
cpp
/*
#include<unistd.h>
int execl(const char *path, const char *arg, ...);
参数:
-path:
需要指定的执行的文件路径或者相对路径的名称
比如a.out 或者/home/linux/a.out
执行a.out的时候可以传递一些参数,所以后面都是可变参数
-arg:
是执行可执行文件需要的参数列表
第一个参数一般没有什么作用,为了方便,一般写的是程序的名称、
从第二个参数开始往后,就是程序执行所需要的参数。
参数最后需要以NULL结束(哨兵)。
返回值:
只有出错的时候才会有返回值,返回-1,并且设置errno。
如果调用成功,没有返回值。
为什么没有返回值?因为用户区的内容已经被替换了。
*/
#include <unistd.h>
#include <stdio.h>
#include<sys/types.h>
int main() {
// 创建一个子进程,在子进程中执行exec函数族中的函数
pid_t pid = fork();
if(pid > 0) {
// 父进程
printf("我是父进程, pid : %d\n",getpid());
sleep(1);
}else if(pid == 0) {
// 子进程
execl("hello","hello",NULL);
//也可以试着跑一下系统的shell命令,也就是ps aux查看进程的命令,ps是可执行文件,aux是参数。
//execl("/bin/ps", "ps", "aux", NULL);
}
for(int i = 0; i < 3; i++) {
printf("i = %d, pid = %d\n", i, getpid());
}
return 0;
}
运行./exec,会发现输出了hello,world! 并且只有父进程在输出for循环,子进程因为跳出实现另一个进程,不会再往下执行了。
下面的execlp
函数则是到环境变量(输入env 即可查看环境变量,可以看到ps的环境变量是/usr/local/bin,所以下面的代码是可以成功找到ps并且执行的。)中去找可执行文件,所以不需要路径。
cpp
/*
#include <unistd.h>
int execlp(const char *file, const char *arg, ... );
- 会到环境变量中查找指定的可执行文件,如果找到了就执行,找不到就执行不成功。
- 参数:
- file:需要执行的可执行文件的文件名
a.out
ps
- arg:是执行可执行文件所需要的参数列表
第一个参数一般没有什么作用,为了方便,一般写的是执行的程序的名称
从第二个参数开始往后,就是程序执行所需要的的参数列表。
参数最后需要以NULL结束(哨兵)
- 返回值:
只有当调用失败,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值。
int execv(const char *path, char *const argv[]);
argv是需要的参数的一个字符串数组
char * argv[] = {"ps", "aux", NULL};
execv("/bin/ps", argv);
*/
#include <unistd.h>
#include <stdio.h>
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("ps", "ps", "aux", 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;
}