ececl,execlp,execle,execv,execvp //库函数
execve //系统调用
1.execl
which ps
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{printf("main pid=%d\n",getpid());execl("/usr/bin/ps","ps","-f",(char *)0);exit(0);
}
注意,就是原来的程序换成了ps程序,但是PCB没有改变,但是PCB里面的有些值被修改了,比如pcb中程序的名字换成了新进程的名字;
思考1,新的进程从哪里执行呢?
新的进程从主函数的第一行开始执行,也就是ps程序的主函数的第一行代码开始执行,这个和fork方法不一样,fork返回以后,从fork所在位置开始执行; 所以可以直接在execl下面打印一个失败,如果成功就根本不会执行到这里; printf("execl error\n");
思考2:如果将execl里面的第二个参数改为"abc",程序还能否执行?
可以正常执行,只是程序命令改为了abc;
execl("/usr/bin/ps","abc","-f",(char *)0);
思考3:如果将execl里面的第一个参数改为"abc",程序还能否执行?
只要execl第一个参数不出错,第一个参数如果出错了,你就找不到这个程序了; 那么就运行不成功了;比如:
execl("/usr/bin/abc","ps","-f",(char *)0);
一定要在exec替换函数之后写:
printf("exec error!\n");
失败了才运行到这一句.
思考4:去掉\n,会发生什么?
思考5:ps也是由ps.c编译为ps可执行程序的,同理cp也是;
(which ps which cp)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{printf("main pid=%d\n",getpid());execl("/usr/bin/cp","cp","yma.c","ymb.c",(char *)0);exit(0);
}
2.execlp
execlp("ps","ps","-f",(char *)0);
只给文件名,不需要给文件路径,因为它可以去环境变量PATH所指的位置去搜索;
注意,第一句,虽然有两个ps,但是不能省,第一个代表我们启动的是ps(去环境变量下搜索),第二个代表的是替换的程序也就是新程序的名字;
3.execle
和execl一样的参数,只是多了最后一个环境变量.
//int main(int argc,char *argv[],char *envp[])
execle("/usr/bin/ps","ps","-f",(char *)0,envp);
思考:如何使用自己的环境变量呢?
4.execv
execv是把参数都放在了一个数组中,然后把这个数组传递进去即可;
//int main(int argc,char *argv[],char *envp[])char *myargv[]={"ps","-f",0};
execv("/usr/bin/ps",myargv);
5.execvp
第一个参数只要文件名,不要路径;
//int main(int argc,char *argv[],char *envp[])char *myargv[]={"ps","-f",0};
execvp("ps",myargv);
看帮助手册,execvpe是GNU的扩展,不通用,所以我们这里不做介绍.
(但是我们其实已经知道,execvpe比execvp多了一个e,也就是多了一个环境变量)
6.execve(重点)
int execve(const char * path, char* const argv[],char* const envp[]); //系统调用
代码如下:
//int main(int argc,char *argv[],char *envp[])char *myargv[]={"ps","-f",0};
execve("/usr/bin/ps",myargv,envp);
总结:
//pathname:新替换的程序的路径+名字
//arg :传给新程序主函数的第一个参数,一般为程序的名字
//arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数
int execl(const char* pathname, const char * arg,...);
int execlp(const char* file, const char * arg,...);
int execle(const char* pathname, const char * arg,...,char* const envp[]);
int execv(const char * pathname, char* const argv[]);
int execvp(const char * file, char* const argv[]);
int execve(const char * pathname, char* const argv[],char* const envp[]); //系统调用//前五个是库函数,最后一个是系统调用,所以本质上上面5个都是通过第六个系统调用实现的
也就是说,上面5个都是调用的execve,不过都是把参数放进数组,然后把数组传递给这个系统调用execve; 也就是说,这些方法没有本质区别; 也就是说,本质上只有一个替换方法,就是execve;
注意,写一个(char *)NULL也是可以的;
助记:
l(list) 参数地址列表,以空指针结尾
v(vector) 存放各个参数地址的指针数组的地址
p(path) 按PATH环境变量指定的目录搜索可执行文件
e(enviroment) 存放环境变量字符地址的指针数组的地址