和外国人做古玩生意的网站南宁网页制作步骤

当前位置: 首页 > news >正文

和外国人做古玩生意的网站,南宁网页制作步骤,国外设计网站app吗,郑州广告牌制作市场朋友们、伙计们#xff0c;我们又见面了#xff0c;本期来给大家解读一下有关Linux程序替换的相关知识点#xff0c;如果看完之后对你有一定的启发#xff0c;那么请留下你的三连#xff0c;祝大家心想事成#xff01; C 语 言 专 栏#xff1a;C语言#xff1a;从入门…  朋友们、伙计们我们又见面了本期来给大家解读一下有关Linux程序替换的相关知识点如果看完之后对你有一定的启发那么请留下你的三连祝大家心想事成 C 语 言 专 栏C语言从入门到精通 数据结构专栏数据结构 个  人  主  页 stackY、 C 专 栏   C Linux 专 栏  Linux 目录 1. 程序替换

  1. 单进程的程序替换 2.1 单进程程序替换的原理
  2. 多进程的程序替换 3.1 多进程程序替换原理
  3. 剩余接口的介绍以及使用  4.1 execl函数介绍 4.2 execlp函数介绍 4.3 execv函数介绍  4.4 execvp函数介绍 4.5 替换别的程序 
  4. 环境变量和程序替换 5.1 从bash开始继承  5.2 从父进程开始继承  5.3 环境变量默认继承 5.4 execle函数介绍  5.5 execve系统调用  1. 程序替换 我们创建的所有子进程执行的代码都是父进程代码的一部分那么如果我们想让子进程执行新的程序呢执行全新的代码和访问全新的数据不再和父进程有所瓜葛那么就需要用到程序替换。 这么多程序替换的函数调用到底该怎么样用呢我们直接开始使用 2. 单进程的程序替换 为了便于理解我们先从单进程的程序替换开始 int execl(const char *path, const char arg, …); 先来看最简单的程序替换接口其中里面的三个点表示的意思就是可变参数使用的方法和我们的printf函数中的可变参数一样 我们程序要能运行起来第一步先要找到这个程序第二部如何运行。 const char path表示新程序的文件路径 文件名const char *arg表示这个程序怎么运行简单的说我们在命令行怎么输就怎么写最终以NULL结尾。 返回值成功没有返回值失败返回-1。 我们先来演示一遍让ls命令替换掉我们写的可执行 #include stdio.h #include unistd.hint main() {printf(pid: %d, exec command begin\n, getpid());sleep(3);// 程序替换execl(/usr/bin/ls, ls, -a, -l, NULL);printf(pid: %d, exec command begin\n, getpid());return 0; } 通过结果可以发现我们通过execl成功完成了程序替换但是代码中的最后一行代码为什么没有打印出来呢这个到后续再解释 2.1 单进程程序替换的原理 我们已经完成了单进程的程序替换那么它的原理是什么呢 当一个进程运行起来时OS会为它创建PCB、虚拟地址空间、页表将它的代码、数据加载到物理内存中并且然后通过页表建立起虚拟到物理的映射关系当进行程序替换时execl就将要替换的程序代码和数据直接在物理内存中替换覆盖掉此时原来的代码和数据就会被新替换的代码和数据覆盖掉继续向后执行也就执行的新程序的代码和数据这个过程中并没有创建新的进程。 3. 多进程的程序替换 见识过单进程的程序替换以及程序替换的原理接下来替换一下多进程 #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.hint main() {pid_t id fork();if(id 0){// childprintf(pid: %d, exec command begin\n, getpid());sleep(3);// 程序替换execl(/usr/bin/ls, ls, -a, -l, NULL);printf(pid: %d, exec command begin\n, getpid());}// parentpid_t rid waitpid(id, NULL, 0);if(rid id){printf(wait success, rid: %d\n, rid);}return 0; } 3.1 多进程程序替换原理 首先进程具有独立性其次我们都知道父子进程代码共享数据以写时拷贝的方式各自私有一份那么在程序替换的时候把子进程的数据替换这没问题因为父子数据各自私有但是将代码替换这就有点不能忍了父子进程代码共享既然子进程都执行的是替换后的代码为什么父进程在程序替换的时候还是继续执行他自己代码呢 是因为在多进程的程序替换时当子进程启动程序替换覆盖它们的共享代码时也会发生写时拷贝的方式重新开辟一块空间然后进行替换写入这样父子进程的代码就不共享子进程继续执行它替换后的代码父进程继续执行自己的代码。 在替换完之后子进程怎么知道从新程序的哪里开始执行呢 我们的代码在编译形成可执行程序的时候会有一个程序入口地址–entry地址 CPU内部的eip寄存器可以记录我们程序当前运行到哪里了所以当程序替换之后新程序的eip程序计数器就被修改为entry地址所以就可以重新开始运行了。  接下来解决上面遗留的问题 代码中的最后一行代码为什么没有打印出来呢 是因为在程序替换以后代码和数据都被覆盖了所以execl函数替换成功后后续的代码没有机会执行了因为已经被替换掉了 所以我们不用判断它的返回值如果继续执行了后续代码说明程序替换出错了。 4. 剩余接口的介绍以及使用  要完成程序替换需要满足以下两点 1. 必须先要找到需要替换的程序。2. 必须告诉替换函数该怎么执行。 这些程序替换的函数前面的单词都相同主要是后缀不同代表的意思也不同。 4.1 execl函数介绍 execl中的l表示列表的意思在我们传递使用方法的时候就像一个列表一样最后以NULL结尾。也就类似于一个list链表一样。 4.2 execlp函数介绍 execlp中的p表示要找的目标可执行程序会自动在环境变量PATH中根据file去查找。 execlp(ls, ls, -a, -l, NULL); // 两个ls表示的含义不一样 // 第一个表示要执行的文件 // 第二个表示如何执行 4.3 execv函数介绍  execv中v表示的是数组传参的意思可以将如何执行保存一个数组中然后传递该数组即可。 #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.hint main() {pid_t id fork();if(id 0){// childprintf(pid: %d, exec command begin\n, getpid());sleep(3);// 程序替换char *const argv[] {ls,-a,-l,NULL};execv(/usr/bin/ls, argv);printf(pid: %d, exec command begin\n, getpid());}// parentpid_t rid waitpid(id, NULL, 0);if(rid id){printf(wait success, rid: %d\n, rid);}return 0; } 4.4 execvp函数介绍 execvp就是execv和execlp和结合可以直接传递文件名并且执行方式以数组传参的方式传递。 char *const argv[] {ls,-a,-l,NULL};execvp(ls, argv);//execvp(argv[0], argv); 4.5 替换别的程序  程序替换不仅可以替换系统的命令还可以替换我们自己写的任何程序 用C程序来替换C语言程序 #include iostreamint main() {std::cout hello C std::endl;std::cout hello C std::endl;std::cout hello C std::endl;std::cout hello C std::endl;return 0; } #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.hint main() {pid_t id fork();if(id 0){// childprintf(pid: %d, exec command begin\n, getpid());sleep(3);// 程序替换execl(./test, test, NULL);printf(pid: %d, exec command begin\n, getpid());}// parentpid_t rid waitpid(id, NULL, 0);if(rid id){printf(wait success, rid: %d\n, rid);}return 0; } 我们在命令行执行可执行程序时用的是./exe那么为什么在传参时只传递exe因为./表示的意思是先找到该程序在运行execl第一个参数已经找到了所以只需要传递exe即可。 5. 环境变量和程序替换 在环境变量章节说过环境变量具有全局属性那么当我们进行程序替换的时候子进程对应的环境变量是可以直接从父进程中来的父进程的环境变量从bash中来我们可以通过代码来验证一下 5.1 从bash开始继承  同样的我们还是使用程序替换的方式来看看子进程替换之后从bash继承下来的环境变量。 先在命令行自定义一些环境变量 export MYENV11111111111111 export MYENV22222222222222源test.cc #include iostreamint main(int argc, char *argv[], char *env[]) {int i 0;for(; env[i]; i){std::cout env[i] std::endl; // 打印环境变量}return 0; } 源myprocess.c #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.hint main() {pid_t id fork();if(id 0){printf(pid: %d, exec command begin\n, getpid());sleep(1);execl(./test, test, NULL);printf(pid: %d, exec command begin\n, getpid());}pid_t rid waitpid(id, NULL, 0);if(rid id)printf(wait success, rid: %d\n, rid);return 0; } 可以看到父进程继承了bash的环境变量子进程继承了父进程的环境变量。 5.2 从父进程开始继承  在程序中导入环境变量的接口为putenv(); #include stdlib.h int putenv(char *string);在父进程中导入一个环境变量看看子进程能否继承 #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.h #include stdlib.hint main() {char *env_val MYVAL55555555555555555555555555;putenv(env_val);pid_t id fork();if(id 0){printf(pid: %d, exec command begin\n, getpid());sleep(1);execl(./test, test, NULL);printf(pid: %d, exec command begin\n, getpid());}pid_t rid waitpid(id, NULL, 0);if(rid id)printf(wait success, rid: %d\n, rid);return 0; } 5.3 环境变量默认继承 在进程地址空间这一章节我们了解到了进程地址空间中有环境变量和命令行参数在父进程创建子进程的过程中子进程以父进程为模版子进程的地址空间也就以父进程的地址空间为模版创建了进而父进程的环境变量和命令行参数也就都会被继承下来所以通过地址空间可以让子进程继承父进程的环境变量和数据所以说这是一种默认的行为。 那么继承下去的环境变量为什么不会收到程序替换的影响呢环境变量也是数据呀 在程序替换的过程中只会替换程序的代码和数据并不会对环境变量产生影响。 5.4 execle函数介绍  将父进程的环境变量传递给子进程有两种方式 1. 直接使用默认集成需要传。 2. 使用execle函数的第三个参数直接传递。 #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.h #include stdlib.hextern char ** environ; int main() {pid_t id fork();if(id 0){printf(pid: %d, exec command begin\n, getpid());sleep(1);execle(./test, test,NULL, environ); // 直接传printf(pid: %d, exec command begin\n, getpid());}pid_t rid waitpid(id, NULL, 0);if(rid id)printf(wait success, rid: %d\n, rid);return 0; } 如果要传递我们自己的环境变量可以先定义再传递同样我们也可以把命令行参数传递给子进程然后通过程序替换来展现出来 源test.cc #include iostream #include unistd.hint main(int argc, char *argv[], char *env[]) {for(int i 0; i argc ; i){std::cout i - argv[i] std::endl;}std::cout ################################ std::endl;for(int i 0; environ[i]; i){std::cout i : env[i] std::endl;}return 0; } 源process.c #include stdio.h #include unistd.h #include sys/types.h #include sys/wait.h #include stdlib.hint main() {char *const myenv[] {MYVAL111111111111111,MYVAL222222222222222,MYVAL333333333333333,MYVAL444444444444444,NULL};pid_t id fork();if (id 0){printf(pid: %d, exec command begin\n, getpid());sleep(1);execle(./test, test, -a, -b, NULL, myenv); // 直接传printf(pid: %d, exec command begin\n, getpid());}pid_t rid waitpid(id, NULL, 0);if (rid id)printf(wait success, rid: %d\n, rid);return 0; } 可以看到传递的环境变量不是新增而是覆盖是传递 程序替换可以将命令行参数、环境变量通过自己的参数传递给被替换程序的mian函数中 5.5 execve系统调用  朋友们、伙计们美好的时光总是短暂的我们本期的的分享就到此结束欲知后事如何请听下回分解~最后看完别忘了留下你们弥足珍贵的三连喔感谢大家的支持