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

【Linux】进程的程序替换

文章目录

  • 1. 程序替换
    • 1.创建子进程的目的是什么?
    • 2.了解程序是如何进行替换的
    • 3. 程序替换的基本原理
      • 当创建进程的时候,先有进程数据结构,还是先加载代码和数据?
      • 程序替换是整体替换,不是局部替换
      • execl 返回值
    • 4. 替换函数
      • 1. execl
      • 2. execv
      • 3. execlp
      • 4. execvp
      • 5. execle
  • 2. 自定义shell
      • 缓冲区问题
      • fgets 使用出现空格问题
      • 完整代码
      • 动图演示

1. 程序替换

1.创建子进程的目的是什么?

目标:为了让子进程帮父进程执行特定的任务

  • 具体做法:1. 让子进程执行父进程的一部分代码

红框中的代码实际上是父进程的代码,在没有执行fork之前代码就有了,在没有创建子进程之前,父进程的代码加载到内存了,子进程被创建出来是没有独立的代码,这个代码是父进程的代码,父进程通过if判断分流让子进程去跑了

  • 2.创建一个子进程不执行父进程的代码,而是让子进程在磁盘当中执行全新的程序,这种操作称之为进程的程序替换

2.了解程序是如何进行替换的

程序替换函数 execl
输入 man execl 查看程序替换接口

int execl(const char *path, const char *arg, …);
括号内部的 . . . 称为 可变参数列表,可以给c函数传递任意个数的参数
第一个参数为 要执行什么命令
第二个参数 为 要怎样执行程序
最后以NULL结尾表示参数传完了


创建test.c文件并输入以下内容

#include<stdio.h>#include<stdlib.h>#include<unistd.h>int main(){printf("begin......\n");printf("begin......\n");printf("begin......\n");printf("begin......\n");execl("/bin/ls", "ls", "-a", "-l", NULL);printf("end........\n");                                            printf("end........\n");                                            printf("end........\n");                                            printf("end........\n");}

运行可执行程序发现,只有begin 以及执行 ls -l -a显示的指令


再次修改test.c文件内容如下

#include<stdio.h>#include<stdlib.h>#include<unistd.h>int main(){printf("begin......\n");printf("begin......\n");printf("begin......\n");printf("begin......\n");printf("我已经是一个进程啦,我的PID:%d\n",getpid());                                                                                                                                                                      execl("/bin/ls", "ls", "-a", "-l", NULL);printf("end........\n");                                            printf("end........\n");                                            printf("end........\n");                                            printf("end........\n");}

test.c 经过编译形成mytest可执行程序,./可执行程序就变成进程了,CPU调度进程 ,打印出代码中的打印语句,同时调用程序替换execl,将ls程序执行起来了


[yzq@VM-8-8-centos nn]$ file /bin/ls
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c8ada1f7095f6b2bb7ddc848e088c2d615c3743e, stripped

使用的 /bin/ls 命令 实际上是一个可执行程序,所以ls程序是在磁盘上的


前面执行的是自己代码的一部分,当调用execl时,将磁盘中可执行程序替换当前进程的代码和数据
后半部分就不执行自己的代码了,执行ls所对应的代码 ,这个现象就叫做程序替换

程序替换就是让一个进程去执行另一个在磁盘中的程序,让一个进程把一个新的程序运行起来

3. 程序替换的基本原理

在这里插入图片描述
当前的进程执行当前代码时,如果执行了函数execl等接口,就会根据你所传入的程序的路径以及你要执行的名称及选项,把磁盘当中的一个其他的程序加载到对应的内存,
用新程序的代码替换当前进程的代码段,用当前进程的数据替换老进程的数据段


站在进程的角度
进程的程序替换有没有创建新的进程呢?
没有,只是将新的程序加载到当前进程的代码段和数据段,用CPU去调度当前进程就可以跑起来了


站在程序的角度
程序被加载了内存中,就可以称程序替换的接口(execl) 为加载器

当创建进程的时候,先有进程数据结构,还是先加载代码和数据?

修改test.c文件为以下内容

#include<stdio.h>2    #include<stdlib.h>3   #include<unistd.h>4    int main()5    {6        execl("/bin/ls", "ls", "-a", "-l", NULL);                                                                                                                                          7   }

此时运行可执行程序,自己就写了一个ls命令


创建子进程,让子进程调用execl,在调用execl把代码和数据加载到内存
所以当创建进程的时候,先有进程数据结构,再加载代码和数据

程序替换是整体替换,不是局部替换

修改test.c文件内容如下

 #include<stdio.h>2    #include<stdlib.h>3   #include<unistd.h>4 #include<sys/wait.h>5    int main()6    {7      pid_t id=fork();8      if(id==0)9      {10        //child11        printf("我是子进程:%d\n",getpid());12        execl("/bin/ls", "ls", "-a", "-l", NULL);                        13      }sleep(5);14      printf("我是父进程:%d\n",getpid());15      waitpid(id,NULL,0);                                                                                                                                                                16   }  

查看子进程完成替换后会不会影响父进程,如果影响父进程,就不应该打印父进程的这句话了


过了5秒钟,父进程结果打印出来,说明父进程不受子进程影响


程序替换只会影响调用进程,进程具有独立性
父子进程都有自己独立的PCB 地址空间 页表 也会自己的映射关系
虽然代码有可能是跟父进程共享,当子进程进行程序替换的时候,子进程会加载新进程的代码和数据
操作系统会发生写时拷贝,将代码和数据进行区分 ,使子进程形成新的映射关系,从而使子进程不会影响到父进程

execl 返回值

如果出错了,execl返回值为-1


修改test.c文件内容如下

#include<stdio.h>2    #include<stdlib.h>3   #include<unistd.h>4 #include<sys/wait.h>5    int main()6    {7      pid_t id=fork();8      if(id==0)9      {10        //child11        printf("我是子进程:%d\n",getpid());12       int n=execl("/bin/lsss", "lsss", "-a", "-l", NULL);//lsss命令不存在     13        printf("you can see me:%d\n",n);14        exit(0);15      }16      sleep(5);17      printf("我是父进程:%d\n",getpid());                                                                                                                                                18      waitpid(id,NULL,0);                                                                                                                            19   }                                                                                                                                                 20      

输入的lsss命令不存在,查询报错后的execl的返回值


程序替换只要成功,就会跑去执行新程序,失败了就会继续向后运行
所以execl程序替换成功不会有返回值——>如果替换失败,一定有返回值——>如果失败了,必定返回——>只要有返回值就失败了
说明不用对execl函数的返回值进行判断,只要继续向后运行一定失败

4. 替换函数

1. execl

int execl(const char *path, const char *arg, …);
l 代表 list 链表
path:代表你想执行谁 (需要带路径)
执行一个程序最基本的原则为:找到它,加载执行它
arg:你想怎么执行它(若想执行ls指令,是只执行ls,还是执行ls- l 、ls -l -a指令
在命令行怎么执行这个命令,就把参数一个一个的传递给execl就可以了
最终以NULL结尾


具体的实现以及返回值问题上面在演示程序替换时已经使用过啦

2. execv

int execv(const char *path, char *const argv[]);
v代表vector 容器
path:代表你想执行谁 (需要带路径)
把原来需要一个一个传的参数放在argv[]数组中


修改test.c文件内容

1    #include<stdio.h>2    #include<stdlib.h>3   #include<unistd.h>4 #include<sys/wait.h>5    int main()6    {7      pid_t id=fork();8      if(id==0)9      {10        //child11        printf("我是子进程:%d\n",getpid());12        char *const myargv[]={"ls", "-l", "-a",NULL};
13       execv("/bin/ls",myargv);14        exit(0);15      }16      sleep(5);17      printf("我是父进程:%d\n",getpid());18      waitpid(id,NULL,0);19   }20                                                                                                                                                                                       

执行可执行程序,依旧可以执行ls指令

3. execlp

int execlp(const char *file, const char *arg, …);
带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
file: 不需要传路径,只需要把在PATH环境变量的指令传过来
最后以NULL结尾


   #include<stdio.h>  2    #include<stdlib.h>  3   #include<unistd.h>  4 #include<sys/wait.h>  5    int main()  6    {  7      pid_t id=fork();  8      if(id==0)  9      {  10        //child  11        printf("我是子进程:%d\n",getpid());  12        execlp("ls", "ls", "-l", "-a",NULL);13        exit(0);14      }15      sleep(5);                                                                                                                                                                          16      printf("我是父进程:%d\n",getpid());                                                              17      waitpid(id,NULL,0);                                                                              18   }   

执行可执行程序,依旧可以执行ls指令


4. execvp

int execvp(const char *file, char *const argv[]);
带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
v代表vector 容器


     #include<stdio.h>    #include<stdlib.h>    #include<unistd.h>    #include<sys/wait.h>    int main()    {    pid_t id=fork();    if(id==0)    {    //child    printf("我是子进程:%d\n",getpid());    char* const myargv[]={"ls", "-l", "-a",NULL};    execvp("ls", myargv);    exit(0);    }    sleep(5);    printf("我是父进程:%d\n",getpid());    waitpid(id,NULL,0);                                                                                                                                                                  }    

在这里插入图片描述

5. execle

int execle(const char *path, const char *arg,
…, char * const envp[]);
path:代表你想执行谁 (需要带路径)
envp[]:代表自定义环境变量
如果调用程序替换时,若不想让子进程使用父进程的环境列表,想自定义环境变量,就可以自己传一个环境变量


在另一个目录中创建other.cc (以cc为结尾说明是一个c++程序),并输入以下内容

#include <iostream>    
#include <unistd.h>    
#include<stdlib.h>    
using namespace std;    int main()    
{    for(int i = 0; i < 5; i++)    {    cout<< "我是另一个程序,我的pid是:"<< getpid()<<endl;                                                                                                                                 cout << " MYENV: " << (getenv("MYENV")==NULL?"NULL":getenv("MYENV")) << endl;    sleep(1);                                        }                                                    return 0;                                            
}               

修改test.c文件为以下内容

     #include<stdio.h>    #include<stdlib.h>    #include<unistd.h>    #include<sys/wait.h>    int main()    {    pid_t id=fork();    if(id==0)    {    //child    printf("我是子进程:%d\n",getpid());    
W>       char*const myenv[]={"MYENV=YouCanSeeMe", NULL};    execle("/home/mydir/my/mm/myother", "myother", NULL,myenv);    exit(0);    }    sleep(1);    printf("我是父进程:%d\n",getpid());    int  status=0;    waitpid(id,&status,0);    return 0;                                                                                                                                                                            }                                                                                                                                                                   

在这里插入图片描述

第一个路径为other.cc生成的可执行程序 myother 所在的 绝对路径



2. 自定义shell

编写极简版本的shell(bash)
目标:为了深刻的理解shell的运行原理


输入 ps ajx |grep bash ,发现bash就是一个进程

在这里插入图片描述


由于shell是一个进程,所以用while死循环

缓冲区问题


在这里插入图片描述
正常来说,运行可执行程序会显示命令行,但是由于没有\n刷新缓冲区,也没有使用相关的刷新库函数,所以命令行会一直在缓冲区中 直到 程序结束才显示,但是这是个死循环,所以什么都不会显示


在这里插入图片描述


在这里插入图片描述


执行可执行程序后即可显示命令行

fgets 使用出现空格问题

fgets 标准输入 按行获取
char *fgets(char *s, int size, FILE *stream);
从特定的标准输入当中获取对应的命令行输入,把对应的数据放在缓冲区中




执行可执行程序后,发现在命令行中输入 ls -a ,就会打印出 ls -a,但是输入时会多出一个空行


在这里插入图片描述

正常来说,都会使用回车来到下一行,而这个回车被fgets读取到了


在这里插入图片描述
将最后的回车符替换成’\0’


在这里插入图片描述
此时就没有空格出现了

完整代码

: mybash.c ? ?                                                                                                                                                                ?? buffers #include<stdio.h>#include<unistd.h>#include<string.h>#include<assert.h>#include<sys/types.h>#include<sys/wait.h>#include<stdlib.h>#define MAX 1024#define ARGC 64#define SEP " "int split (char*commandstr,char*argv[]){assert(commandstr);assert(argv);argv[0]=strtok(commandstr,SEP);//在commandstr以空格作为分割符if(argv[0]==NULL)//切割失败{return -1;}int i=1;while(1){argv[i]=strtok(NULL,SEP);//继续切割空格if(argv[i]==NULL){break; }i++;                                                                                                                                                                                 }
W>}void print(char*argv[]){int i=0;for(i=0;argv[i];i++){                                                                                                                                                                                       printf("%d:%s\n",i,argv[i]);}}int main(){   while(1){char commandstr[MAX]={0};char*argv[ARGC]={NULL};printf("[yzq@mymachine currpath]# ");fflush(stdout);char*s= fgets(commandstr,sizeof(commandstr),stdin);assert(s);(void)s;//保证在release方式发布的时候,因为去掉assert了,所以s就没有被使用,而带来的编译告警, 什么都没做,但是充当一次使用commandstr[strlen(commandstr)-1]='\0';//将最后的回车符用'\0'覆盖掉int n= split(commandstr,argv); //从命令行中获取的字符串传入argv中if(n!=0)continue;//切割失败就什么都不做// print(argv);//打印字符串pid_t id=fork();assert(id>=0);(void)id;if(id==0){//childexecvp(argv[0],argv);exit(1);}int status=0;waitpid(id,&status,0);}}

动图演示

在这里插入图片描述

相关文章:

【Linux】进程的程序替换

文章目录1. 程序替换1.创建子进程的目的是什么&#xff1f;2.了解程序是如何进行替换的3. 程序替换的基本原理当创建进程的时候&#xff0c;先有进程数据结构&#xff0c;还是先加载代码和数据&#xff1f;程序替换是整体替换&#xff0c;不是局部替换execl 返回值4. 替换函数1…...

【C++】模板(上)

文章目录1、泛型编程2、函数模板函数模板的实例化模板参数的匹配原则3、 类模板类模板的实例化1、泛型编程 void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left …...

express框架利用formidable上传图片

express框架&#xff0c;在上传图片功能方面&#xff0c;用formidable里面的incomingform功能&#xff0c;很方便。很多功能都已经封装好了&#xff0c;非常好用&#xff0c;简单&#xff0c;不需要写更深层次的代码了。确实不错。 下面是我自己跟着黑马教程的博客系统的部分&…...

测试背锅侠?入职软件测试后大d佬给我丢了这个bug分类分析,至今受益匪浅......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 刚成为入职&#xf…...

STM32 OTA应用开发——通过内置DFU实现USB升级(方式1)

STM32 OTA应用开发——通过内置DFU实现USB升级&#xff08;方式1&#xff09; 目录STM32 OTA应用开发——通过内置DFU实现USB升级&#xff08;方式1&#xff09;前言1 硬件介绍2 环境搭建2.1 Keil uVsion2.2 zadig2.3 STM32CubeProgrammer2.4 安装USB驱动3 OTA升级结束语前言 …...

基于MFC的JavaScript进行网页数据交互

目录 前言 一、创建html对话框工程 二、使用步骤 1.引入JavaScript接口代码 2.重写相关接口 3.在html网页中添加C/C调用的接口 4.在MFC工程中添加调用接口 5.设置确认按键触发调用 6.运行结果 总结 前言 如何快速的进行MFC开发,这里我介绍一种JavaScript与C/C交互的…...

AUTOSAR-Fee

Fee模块 全称Flash EEPROM Emulation Module,属于ECU抽象层 Fee模块本身是脱离硬件的,但是Fee模块可能会引用的Fls模块定制API,所以只能算半抽象. FEE模块应从设备特定的寻址方案和分段中抽象出来,并为上层提供虚拟寻址方案和分段(virtual addressing scheme and segment…...

Linux基本命令——操作演示

Linux基本命令——操作演示Linux的目录结构Linux命令入门目录切换相关命令&#xff08;cd/pwd&#xff09;相对路径、绝对路径和特殊路径符创建目录命令&#xff08;mkdir&#xff09;文件操作命令part1 (touch、cat、more)文件操作命令part2 (cp、mv、rm&#xff09;查找命令 …...

【Linux】目录和文件的权限

Linux中的权限有什么作用Linux权限管理文件访问者的分类文件类型和访问权限&#xff08;事物属性&#xff09;**文件权限值的表示方法**文件访问权限的相关设置方法chmodchownchgrpumaskumask使用 sudo分配权限目录的权限Linux中的权限有什么作用 Linux下有两种用户&#xff1…...

Unity 优化之Player Setting

Quality SettingPixel Light Count 使用前向渲染时最大像素光源数。也是性能关键。数量越大消耗越多。Texture Quality&#xff1a;贴图质量&#xff0c;可以选择Half Res&#xff0c;这样速度会更快&#xff0c;但是贴图质量会轻微下降。Anisotropic Textures 纹理各向异形Ant…...

Qt——通过一个简单的程序例程熟悉使用Qt Creator软件进行项目搭建的基本流程(新建项目、项目的文件组成、修改ui文件、编译运行与调试)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》...

Linux 如何使用 git | 新建仓库 | git 三板斧

文章目录 专栏导读 一、如何安装 git 二、注册码云账号 三、新建仓库 配置仓库信息 四、克隆远端仓库到本地 五、git 三板斧 1. 三板斧第一招&#xff1a;git add 2. 三板斧第二招&#xff1a;git commit 解决首次 git commit 失败的问题 配置机器信息 3. 三…...

3.springcloud微服务架构搭建 之 《springboot自动装配ribbon》

1.springcloud微服务架构搭建 之 《springboot自动装配Redis》 2.springcloud微服务架构搭建 之 《springboot集成nacos注册中心》 ribbon工作原理自己网上百度&#xff0c;说的都很详细 目录 1.项目引入openfeign和ribbon配置 2.新建lilock-ribbon-spring-boot-starter 3…...

【一】进程到底是个啥?

1. 什么是进程 进程&#xff08;process&#xff09;&#xff1a;一个运行起来的程序&#xff0c;就是进程&#xff01;&#xff0c;我们可以在任务管理中看到进程。 进程是操作系统进行资源分配的基本单位 2. 进程的管理 所谓的进程管理&#xff0c;其实就是分为两步&…...

[蓝桥杯] 双指针、BFS和DFS与图论问题

文章目录 一、日志统计 1、1 题目描述 1、2 题解关键思路与解答 二、献给阿尔吉侬的花束 2、1 题目描述 2、2 题解关键思路与解答 三、红与黑 3、1 题目描述 3、2 题解关键思路与解答 3、2、1 dfs题解代码 3、2、2 bfs题解答案 四、交换瓶子 4、1 题目描述 4、2 题解关键思路与…...

编译原理陈火旺版第四章课后题答案

下面答案仅供参考&#xff01; 1.考虑下面文法G1: (1) 消去 Q 的左递归。然后&#xff0c;对每个非终结符&#xff0c;写岀不带回溯的递归子程序。 (2) 经改写后的文法是否是LL(1)的&#xff1f;给出它的预测分析表。 2.对下面的文法G: P→(E)lalblΛ (1)计算这个文法的每个非…...

【LeetCode】剑指 Offer(25)

目录 题目&#xff1a;剑指 Offer 49. 丑数 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;剑指 Offer 49. 丑数 - 力扣&…...

【数据结构】链表OJ

Yan-英杰的主页 悟已往之不谏 知来者之可追 目录 ​编辑 ​编辑二、分享&#xff1a;OJ调试技巧 ​编辑三、链表的中间结点 ​编辑四、链表中倒数第k个结点 一、移除链表元素 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,…...

电子工程师必须掌握的硬件测试仪器,你确定你都掌握了?

目录示波器示例1&#xff1a;测量示波器自带的标准方波信号输出表笔认识屏幕刻度认识波形上下/左右移动上下/左右刻度参数调整通道1的功能界面捕获信号设置Menu菜单触发方式触发电平Cursor按钮捕捉波形HLEP按钮参考资料频谱分析仪器信号发生器示波器 示例1&#xff1a;测量示波…...

高速PCB设计指南系列(四)

第二篇 抗干扰3&#xff08;部分&#xff09; 3 提高敏感器件的抗干扰性能 提高敏感器件的抗干扰性能是指从敏感器件这边考虑尽量减少对干扰噪声 的拾取&#xff0c;以及从不正常状态尽快恢复的方法。 提高敏感器件抗干扰性能的常用措施如下&#xff1a; &#xff08;1&…...

ODrive入门配置

目录一、驱动板说明二、安装python三、安装odrivetool四、接线五、zadig设置SimpleFOC、ODrive和VESC教程链接汇总&#xff1a;请点击一、驱动板说明 ODrive 硬件版本&#xff1a;V3.6-56V&#xff0c; 工作电压&#xff1a;12V-56V&#xff0c; 工作电流&#xff1a;60A ODri…...

快速测试两台服务器间的网速(ChatGPT回复)

如何使用iperf3测试从远程服务器下载文件速度 在进行网络性能测试时&#xff0c;了解服务器之间的带宽和延迟是非常重要的。iperf3是一种用于测量网络性能的工具&#xff0c;可以帮助我们测试从远程服务器下载文件的速度。本文将介绍如何在本地计算机上使用iperf3测试从远程服…...

彻底搞懂nodejs事件循环

nodejs是单线程执行的&#xff0c;同时它又是基于事件驱动的非阻塞IO编程模型。这就使得我们不用等待异步操作结果返回&#xff0c;就可以继续往下执行代码。当异步事件触发之后&#xff0c;就会通知主线程&#xff0c;主线程执行相应事件的回调。 以上是众所周知的内容。今天…...

Linux基础命令大全(下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…...

Matplotlib从入门到精通05-样式色彩秀芳华

Matplotlib从入门到精通05-样式色彩秀芳华总结Matplotlib从入门到精通05-样式色彩秀芳华导入依赖一、matplotlib的绘图样式&#xff08;style&#xff09;1.matplotlib预先定义样式2.用户自定义stylesheet3.设置rcparams二、matplotlib的色彩设置&#xff08;color&#xff09;…...

< CSS小技巧:那些不常用,却很惊艳的CSS属性 >

文章目录&#x1f449; 前言&#x1f449; 一. background-clip: text - 限制背景显示&#xff08;裁剪&#xff09;&#x1f449; 二. user-select - 控制用户能否选中文本&#x1f449; 三. :focus-within 伪类&#x1f449; 四. gap - 网格 / 弹性布局间隔设置&#x1f449;…...

GPT-4 重磅发布,用户直呼:强得离谱

ChatGPT沉寂了一会&#xff0c;OpenAI 的新“核弹”又来了&#xff0c;GPT-4&#xff0c;并且它还非常擅长编码。闲话不提&#xff0c;直捣黄龙。 OpenAI 宣布发布 GPT-4 ChatGPT-4这是 OpenAI 努力扩展深度学习的最新里程碑&#xff0c;GPT-4 是一个大型多模态模型。 据悉&a…...

【JavaSE】知识点总结(3)

目录 一、类定义和使用 1. 类的定义 2. 类的实例化 3. 构造方法 构造方法的重载 二、this关键字 三、 static 修饰属性 四、封装 2. getter与setter 五、继承 1. 继承的语法 2. 子类中访问父类 3. 关于继承原则 4. super关键字 5. super和this 6. protected 关键…...

MySQL基础(三)聚合函数、子查询

目录 聚合函数 AVG/SUM/MAX/MIN COUNT函数 GROUP BY HAVING having和where的区别 SELECT的执行过程 子查询 单行子查询vs多行子查询 单行子查询 多行子查询 关联子查询 EXISTS 与 NOT EXISTS关键字 聚合函数 聚合函数作用于一组数据&#xff0c;并对一组数据返回一个…...

深度学习数据集处理基础内容——xml和json文件详解

文章目录一、xml文件1.1 什么是 XML&#xff1f;1.2XML 和 HTML 之间的差异1.3XML 不会做任何事情1.4通过 XML 您可以发明自己的标签1.5XML 不是对 HTML 的替代1.6XML 无所不在二、json文件基本的JSON结构体类型&#xff08;共享部分&#xff09;三、转COCO数据集3.1 info3.2 l…...

网站建设有那些步骤/永久免费自动建站

2019独角兽企业重金招聘Python工程师标准>>> 因为某个模块下线&#xff0c;项目需要临时搞个阉割版&#xff0c; 所以在命令行里面传一个参数&#xff0c;这样回滚时只要取消参数就可以 java -jar -Dmodedev -DdisableCommonConf -Dtrandclose FlowX-0.1.jar在代码里…...

印度做网站需要备案吗/网站打开速度优化

引用官方的解释 PHP 在变量定义中不需要&#xff08;或不支持&#xff09;明确的类型定义&#xff1b;变量类型是根据使用该变量的上下文所决定的。也就是说&#xff0c;如果把一个 string 值赋给变量$var&#xff0c;$var 就成了一个 string。如果又把一个integer 赋给 $var&a…...

建国际网站需要多少钱/安徽网站seo公司

如何利用fg迅速回到vim中&#xff1f;当用vim修改某文件中的一个参数时&#xff0c;由于参数很长记不住。往往出现当我们刚刚用vim刚打开这个文件后&#xff0c;就忘记了刚刚的参数。这时我们需要暂时退出这个文件去一个目录中找参数。或者有多次打开关闭同一个文件的操作时。那…...

宁波免费做网站/宁波seo优化公司

绘制环境 getContext(2d)&#xff1a;目前只支持2d场景不能在样式里设置宽高&#xff0c;否则变成等比缩放&#xff08;包括里面画的内容也会等比缩放&#xff09; 复制代码 绘制图形&#xff1a; 绘制方块&#xff1a;fillRect(L,T,W,H); 填充的方块strokeRect(L,T,W,H); 带边…...

个人网站备案icp/泸州网站优化推广

在Access数据库窗体中怎么实现一个文本框中输入内容&#xff0c;在另一个文本框中自动显示其内容。或许这个问题没表述清楚&#xff01;如在窗体中有图号和单件定额这个两项内容&#xff0c;怎样才能实现输入了图号的内容&#xff0c;在单件定额中自动显示出对应的内容呢&#…...

亦庄开发区建设局网站/seo网站优化专员

首先要确保自己的jdk、mysql、idea、maven安装完毕 1.搭建一个提供测试的数据库 CREATE DATABASE mybatis;USE mybatis;DROP TABLE IF EXISTS user;CREATE TABLE user ( id int(20) NOT NULL, name varchar(30) DEFAULT NULL, pwd varchar(30) DEFAULT NULL, PRIMARY KEY (id…...