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

从理论到实践:Linux 进程替换与 exec 系列函数

个人主页:chian-ocean

文章专栏-Linux

前言:

在Linux中,进程替换(Process Substitution)是一个非常强大的特性,它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中。

在这里插入图片描述

进程替换原理

进程替换(Process Replacement)是操作系统用来用一个新程序完全替换当前进程用户态内容的机制,其本质是清空当前进程的用户态内容并加载新程序,同时保留内核态资源(如 PID、文件描述符等)。它通过 exec 系列系统调用实现,以下是进程替换的详细原理。

进程替换的核心是:

  1. 清空当前进程的用户态地址空间,包括代码段、数据段、堆、栈等。
  2. 加载新程序到当前进程的地址空间,并切换到新程序的入口点执行。
  3. 保留进程的内核态资源,如 PID、打开的文件描述符、父子关系等。
  4. 如果 exec 调用成功,原进程的代码永远不会被执行。
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>  using namespace std;int main() {// 输出当前进程的 PID(进程 ID)和 PPID(父进程 ID)cout << "I'm a process: " << "PID: " << getpid() << " PPID: " << getppid() << endl;// 调用 fork() 创建子进程pid_t id = fork();// 子进程逻辑if (id == 0) {cout <<"Child PID: "<< getpid() << endl;//打印子进程的PID// 使用 execl() 替换当前子进程为 /usr/bin/ls 程序// 第一个参数是程序路径,第二个参数是程序名称(通常为 argv[0]),后面是命令行参数execl("/usr/bin/ls", "ls", "-l", "-a", NULL);// 如果 execl() 执行失败(例如文件不存在),会执行以下代码perror("execl failed"); // 输出错误信息exit(1); // 子进程以退出码 1 结束}// 父进程逻辑// 使用 waitpid() 等待子进程结束int ret = waitpid(id, NULL, 0); // 第二个参数为 NULL,表示忽略子进程的退出状态if (ret > 0) {// 如果 waitpid() 成功返回,表示子进程已结束cout << "Father PID: " << getpid() << " " << "Child PID: " << ret << endl;return 0; // 父进程正常退出
}

执行流程

  1. 程序开始
    • 父进程运行,打印自己的 PID 和 PPID(错误地显示 PPID 为自己的 PID)。
  2. 创建子进程
    • fork 创建一个子进程。
  3. 子进程执行 execl
    • 子进程替换为 /usr/bin/ls 程序,并执行 ls -l -a 命令,列出当前目录中所有文件(包括隐藏文件)的详细信息。
    • 如果 execl 成功,子进程的地址空间完全被 ls 程序覆盖。
    • 如果 execl 失败,执行 exit(1),子进程退出,返回码为 1
  4. 父进程等待子进程
    • 父进程调用 waitpid,阻塞等待子进程终止。
    • 当子进程完成后,waitpid 返回子进程的 PID。
  5. 父进程打印结果
    • 父进程输出自己的 PID 和已终止的子进程的 PID。

在这里插入图片描述

  • 子进程的PID没有变化,发成了进程替换。

exec系类函数

exec 系列函数是 UNIX/Linux 系统中用于进程替换的函数集合。通过 exec 系列函数,当前进程的用户态内容(如代码段、数据段、堆、栈等)会被新程序替换,而进程的内核态资源(如 PID、打开的文件描述符等)被保留。

exec 系列函数不创建新进程,只是在当前进程中加载并运行一个新程序。

exec 系列函数的成员

在这里插入图片描述

L:可以理解list

V:可以理解Vector

execl

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

参数说明

  1. path
    • 新程序的文件路径(可以是绝对路径或相对路径)。
    • /bin/ls./myprogram
  2. arg0, ..., NULL
    • 传递给新程序的参数列表,按照顺序传递给新程序的 argv 数组。
    • arg0 通常是程序名,相当于 argv[0]
    • 后续的参数是传递给新程序的命令行参数,相当于 argv[1], argv[2], ...
    • 参数列表必须以 NULL 结束。
  3. 示例:
execl("/bin/ls", "ls", "-l", "-a", NULL);

execlp

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

参数说明

  1. file
    • 新程序的文件名。
    • 如果 file 不包含斜杠(/),execlp 会根据 PATH 环境变量搜索可执行文件。
    • 如果 file 包含斜杠,则直接视为路径,无需搜索 PATH
  2. arg0, ..., NULL
    • 传递给新程序的参数列表,必须以 NULL 结束。
    • arg0 通常是程序名,相当于 argv[0]
    • 后续参数为程序的命令行参数,相当于 argv[1]argv[2] 等。
  3. 示例
execlp("ls", "ls", "-l", "-a", NULL);

execle

int execle(const char *path, const char *arg0, ..., NULL, char *const envp[]);

参数说明:

path

  • 新程序的文件路径,可以是绝对路径或相对路径。
  • /bin/ls./myprogram

arg0, ..., NULL

  • 传递给新程序的参数列表,必须以 NULL 结束。
  • arg0 通常是程序名,相当于 argv[0]
  • 后续参数为程序的命令行参数,相当于 argv[1], argv[2], ...

envp

  • 一个指向环境变量字符串数组的指针。
  • 每个环境变量字符串的格式为 key=value(例如,PATH=/usr/bin)。
  • 如果希望新程序继承当前进程的环境变量,可以手动传递当前进程的 environ
#include<iostream>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>using namespace std;int main()    
{     cout << "I'm a process: "<<"PID:"<<getpid()<< " PPID: "<< getpid()<< endl;    pid_t id = fork();    char *envp[] = {    "MY_VAR=HelloWorld",    "PATH=/bin:/usr/bin",    NULL    };     if(id == 0)    {    cout <<"Child PID: "<< getpid() << endl;    execle("/usr/bin/env","env",NULL,envp);                                  exit(1);    }    int ret = waitpid(id,NULL,0);    if(ret > 0)    cout << "Father PID: "<<getpid()<< " " <<"Child PID: "<< ret << endl;    return 0;    
}

execv

int execv(const char *path, char *const argv[]);

参数说明

  1. path: 指向可执行文件路径的字符串(以 \0 结尾)。
  2. argv: 一个字符串指针数组,用于传递给新程序的参数列表。数组的第一个元素通常为程序名称(argv[0]),最后一个元素必须为 NULL,以标记参数列表结束。

示例:

#include<iostream> 
#include<unistd.h> 
#include<stdlib.h> 
#include<sys/wait.h> 
#include<sys/types.h> int main()
{// 输出当前进程的 PID(进程 ID)和 PPID(父进程 ID)std::cout << "I'm a process: "<< "PID:" << getpid() << " PPID: " << getppid() << std::endl;// 创建子进程pid_t id = fork();// 定义一个字符指针数组,用于存储传递给 `execv` 的参数char *argv[] = {    "ls",    // argv[0]: 通常是程序名称"-l",    // argv[1]: 参数,表示以长格式列出文件"-a",    // argv[2]: 参数,显示隐藏文件NULL     // 终止符,必须为 NULL};if(id == 0) // 子进程执行的代码块{    // 子进程输出自己的 PIDstd::cout << "Child PID: " << getpid() << std::endl; // 用 execv 替换当前进程的执行映像execv("/usr/bin/ls", argv);// 如果 execv 返回,说明执行失败exit(1); // 退出子进程,返回非零值表示错误}// 父进程等待子进程完成int ret = waitpid(id, NULL, 0);if(ret > 0) // 如果 `waitpid` 成功返回std::cout << "Father PID: " << getpid() << " " << "Child PID: " << ret << std::endl;return 0;
}

逐步功能分析

  1. 主进程输出信息
    使用 getpid()getppid() 分别获取当前进程 ID 和父进程 ID,并输出信息。
  2. 创建子进程
    使用 fork() 创建一个子进程:
    • 返回值 id == 0:表示当前是子进程。
    • 返回值 id > 0:表示当前是父进程,id 为子进程的 PID。
  3. 子进程执行新程序
    在子进程中调用 execv
    • 替换当前进程映像为 /usr/bin/ls
    • 参数数组 argv 指定了程序名称和选项。
    • 如果 execv 成功,后续代码不会执行;否则会继续执行并调用 exit(1) 终止子进程。
  4. 父进程等待子进程
    父进程调用 waitpid
    • 阻塞当前进程,直到子进程终止。
    • 返回值 ret 是子进程的 PID。
  5. 父进程输出信息
    输出父进程和子进程的 PID 信息。

在这里插入图片描述

execvp

int execvp(const char *file, char *const argv[]);

参数说明

  1. file
    • 要执行的程序名称或路径。
    • 如果提供的是程序名称(非路径),execvp 会根据环境变量 PATH 中的目录列表查找该程序。
  2. argv
    • 一个字符串数组,表示传递给新程序的参数。
    • argv[0] 通常是程序名称,最后一个元素必须为 NULL

execvpexecv 的区别

  • execv
    要求指定程序的完整路径,且不会从环境变量 PATH 中查找。
  • execvp
    可以仅提供程序名称,函数会自动从 PATH 中查找程序。
#include<iostream> 
#include<unistd.h> 
#include<stdlib.h> 
#include<sys/wait.h> 
#include<sys/types.h> int main()
{// 输出当前进程的 PID(进程 ID)和 PPID(父进程 ID)std::cout << "I'm a process: "<< "PID:" << getpid() << " PPID: " << getppid() << std::endl;// 创建子进程pid_t id = fork();// 定义一个字符指针数组,用于存储传递给 `execv` 的参数char *argv[] = {    "ls",    // argv[0]: 通常是程序名称"-l",    // argv[1]: 参数,表示以长格式列出文件"-a",    // argv[2]: 参数,显示隐藏文件NULL     // 终止符,必须为 NULL};if(id == 0) // 子进程执行的代码块{    // 子进程输出自己的 PIDstd::cout << "Child PID: " << getpid() << std::endl; // 用 execvp 替换当前进程的执行映像execvp("ls", argv); // 区别于execv// 如果 execv 返回,说明执行失败exit(1); // 退出子进程,返回非零值表示错误}// 父进程等待子进程完成int ret = waitpid(id, NULL, 0);if(ret > 0) // 如果 `waitpid` 成功返回std::cout << "Father PID: " << getpid() << " " << "Child PID: " << ret << std::endl;return 0;
}

ecexvpe

int execvpe(const char *file, char *const argv[], char *const envp[]);

参数说明

  1. file
    • 要执行的程序名称或路径。
    • 如果提供的是程序名称,execvpe 会根据环境变量 PATH 自动查找该程序。
  2. argv
    • 一个字符串数组,用于传递给新程序的参数。
    • argv[0] 通常是程序的名称,最后一个元素必须是 NULL
  3. envp
    • 一个字符串数组,用于指定新程序的环境变量。
    • 每个字符串的格式为 KEY=VALUE,例如 "PATH=/usr/bin"
    • 最后一个元素必须为 NULL

示例

#include<iostream>  
#include<unistd.h>   
#include<stdlib.h>   
#include<sys/wait.h> 
#include<sys/types.h>using namespace std;int main()                                                                    
{                     // 输出当前进程的 PID 和父进程 ID(PPID)cout << "I'm a process: "<< "PID:" << getpid() << " PPID: " << getpid() << endl;// 创建子进程pid_t id = fork();      // 自定义环境变量数组char *envp[] = {"MY_VAR=HelloWorld", // 自定义变量 MY_VAR,值为 "HelloWorld""PATH=/bin:/usr/bin", // 自定义 PATH,确保能找到可执行文件NULL                 // 终止标志};       // 命令参数数组,传递给 `ls` 命令char *argv[] = {"ls",   // argv[0] 通常为程序名称"-l",   // 参数:长格式输出"-a",   // 参数:显示隐藏文件NULL    // 终止标志};                                          if(id == 0) // 子进程{cout <<"Child PID: " << getpid() << endl;// 使用 execvpe 执行 ls 命令,传递自定义环境变量execvpe("ls", argv, envp);// 如果 execvpe 执行失败exit(1); // 退出子进程,返回非零值表示错误}                                                                    // 父进程等待子进程完成int ret = waitpid(id, NULL, 0);if(ret > 0) // 如果子进程正常退出cout << "Father PID: " << getpid() << " " << "Child PID: " << ret << endl;return 0

功能分析

  1. 父进程输出信息

    • 使用 getpid() 获取当前进程的 ID。
    • 使用 getpid() 显示父进程的 PPID(此处写错,正确用法应是 getppid())。
  2. 创建子进程

    • 调用

      fork()
      

      创建子进程:

      • 返回值 id == 0:表示当前是子进程。
      • 返回值 id > 0:表示当前是父进程,id 为子进程的 PID。
  3. 定义环境变量和参数

    • envp
      

      是自定义的环境变量数组:

      • 包括 MY_VAR=HelloWorldPATH=/bin:/usr/bin
    • argv
      

      是传递给

      execvpe
      

      的参数列表:

      • 包括 ls 命令及其参数 -l-a
  4. 子进程执行新程序

    • 子进程调用

      execvpe("ls", argv, envp)
      
      • 替换当前子进程的映像为 ls 命令。
      • 使用自定义的环境变量。
    • 如果 execvpe 失败,子进程调用 exit(1) 退出。

  5. 父进程等待子进程完成

    • 调用 waitpid 等待子进程完成。
    • 输出父进程和子进程的 PID 信息。

在这里插入图片描述

exec 系列函数总结

函数名称程序路径参数传递环境变量特点
execl完整路径列表传参继承父进程环境手动传递每个参数;易用但不适合动态参数数量。
execlp搜索 PATH列表传参继承父进程环境PATH 中查找程序;适合提供命令名称的情况。
execle完整路径列表传参自定义环境execl 类似,但支持自定义环境变量。
execv完整路径数组传参继承父进程环境参数通过数组传递,适合动态生成参数的情况。
execvp搜索 PATH数组传参继承父进程环境PATH 中查找程序,适合命令名称和动态参数。
execve完整路径数组传参自定义环境底层实现函数;用户可完全控制路径、参数和环境变量。
execvpe搜索 PATH数组传参自定义环境GNU 扩展,结合 execvpexecve 的优点。

相关文章:

从理论到实践:Linux 进程替换与 exec 系列函数

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;进程替换&#xff08;Process Substitution&#xff09;是一个非常强大的特性&#xff0c;它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中…...

3 卷积神经网络CNN

1 Image Classification (Neuron Version) – 1.1 Observation 1 1.2 Observation 2 如果不同的receptive field需要相同功能的neuron&#xff0c;可以使这些neuron共享参数 1.3 Benefit of Convolutional Layer 2 Image Classification (Filter Version) 不用担心filter大小…...

详解Linux系统的终端(Terminal)以及分类(各种tty开头的设备文件)

目录 终端(Terminal)的概念和作用终端(Terminal)在Linux中被视为设备,每个终端有自己的设备文件tty三个字母的来源(tty名字的来源)如何查看当前终端的设备文件常见终端的分类1-串口终端02-虚拟控制台终端&#xff08;Virtual Console&#xff09;03-伪终端&#xff08;Pseudo T…...

强化学习数学原理(五)——随机近似与随机

一、Motivating example 首先有个random variable(随机变量)X&#xff0c;我们的目标就是求出他的expectation E(x)&#xff0c;我们有一些iid的采样&#xff0c;xi&#xff0c;从1到n&#xff0c;求出均值 但是如果有很多数据&#xff0c;我需要等很久&#xff0c;把所有数据都…...

图书管理系统 Axios 源码__获取图书列表

目录 核心功能 源码介绍 1. 获取图书列表 技术要点 适用人群 本项目是一个基于 HTML Bootstrap JavaScript Axios 开发的图书管理系统&#xff0c;可用于 添加、编辑、删除和管理图书信息&#xff0c;适合前端开发者学习 前端交互设计、Axios 数据请求 以及 Bootstrap 样…...

线性数据结构:单向链表

放弃眼高手低&#xff0c;你真正投入学习&#xff0c;会因为找到一个新方法产生成就感&#xff0c;学习不仅是片面的记单词、学高数......只要是提升自己的过程&#xff0c;探索到了未知&#xff0c;就是学习。 考虑到可能有小白在合并代码时出现各种细节问题&#xff0c;本文…...

线程互斥同步

前言&#xff1a; 简单回顾一下上文所学&#xff0c;上文我们最重要核心的工作就是介绍了我们线程自己的LWP和tid究竟是个什么&#xff0c;总结一句话&#xff0c;就是tid是用户视角下所认为的概念&#xff0c;因为在Linux系统中&#xff0c;从来没有线程这一说法&#xff0c;…...

《苍穹外卖》项目学习记录-Day11订单统计

根据起始时间和结束时间&#xff0c;先把begin放入集合中用while循环当begin不等于end的时候&#xff0c;让begin加一天&#xff0c;这样就把这个区间内的时间放到List集合。 查询每天的订单总数也就是查询的时间段是大于当天的开始时间&#xff08;0点0分0秒&#xff09;小于…...

SAP HCM 回溯分析

最近总有人问回溯问题&#xff0c;今天把12年总结的笔记在这共享下&#xff1a; 12年开这个图的时候总是不明白是什么原理&#xff0c;教程看N次&#xff0c;网上资料找一大堆&#xff0c;就是不明白原理&#xff0c;后来为搞明白逻辑&#xff0c;按照教材的数据一样做&#xf…...

JavaScript原型链与继承:优化与扩展的深度探索

在 JavaScript 的世界里&#xff0c;万物皆对象&#xff0c;而每个对象都有一个与之关联的原型对象&#xff0c;这就构成了原型链的基础。原型链&#xff0c;简单来说&#xff0c;是一个由对象的原型相互连接形成的链式结构 。每个对象都有一个内部属性[[Prototype]]&#xff0…...

五子棋对弈

问题描述 "在五子棋的对弈中&#xff0c;友谊的小船说翻就翻&#xff1f;" 不&#xff01;对小蓝和小桥来说&#xff0c;五子棋不仅是棋盘上的较量&#xff0c;更是心与心之间的沟通。这两位挚友秉承着"友谊第一&#xff0c;比赛第二"的宗旨&#xff0c;决…...

vue vscode插件推荐安装

在 VSCode 中开发 Vue&#xff0c;推荐安装以下插件&#xff1a; 核心插件 1. Volar&#xff08;Vue Language Features&#xff09; - Vue 3 官方推荐的开发工具&#xff0c;替代 Vetur。 This extension is deprecated. Use the Vue - Official extension instead. 1.Vue …...

Med-R2:基于循证医学的检索推理框架:提升大语言模型医疗问答能力的新方法

Med-R2 : Crafting Trustworthy LLM Physicians through Retrieval and Reasoning of Evidence-Based Medicine Med-R2框架Why - 这个研究要解决什么现实问题What - 核心发现或论点是什么How - 1. 前人研究的局限性How - 2. 你的创新方法/视角How - 3. 关键数据支持How - 4. 可…...

P7497 四方喝彩 Solution

Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1​,a2​,⋯,an​)&#xff0c;有 m m m 个操作&#xff0c;分四种&#xff1a; add ⁡ ( l , r , v ) \operatorname{add}(l,r,v) add(l,r,v)&#xff1a;对于所有 i ∈ [ l , r ] i \in [l,r…...

EtherCAT主站IGH-- 29 -- IGH之mailbox.h/c文件解析

EtherCAT主站IGH-- 29 -- IGH之mailbox.h/c文件解析 0 预览一 该文件功能`mailbox.c` 文件功能函数预览二 函数功能介绍`mailbox.c` 中主要函数的作用1. `ec_slave_mbox_prepare_send`2. `ec_slave_mbox_prepare_check`3. `ec_slave_mbox_check`4. `ec_slave_mbox_prepare_fetc…...

UI线程用到COM只能选单线程模型

无论用不用UI库&#xff0c;哪怕是用Win32 API手搓UI&#xff0c;UI线程要用COM的话&#xff0c;必须初始化为单线程单元(STA)&#xff0c;即CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);&#xff0c;不能用MULTITHREADTHREADED。 实际上&#xff0c;很多(WPF等)UI库若…...

排序算法--桶排序

核心思想为分区间排序后合并。适用于数据均匀分布在一个范围内&#xff0c;或浮点数排序或范围明确的数据。如果需要处理整数或其他数据范围&#xff0c;可以通过调整BUCKET_RANGE的计算方式实现&#xff0c;例如对[0,100)的整数排序&#xff1a; int index arr[i] / 10; // …...

zsh安装插件

0 zsh不仅在外观上比较美观&#xff0c;而且其具有强大的插件&#xff0c;如果不使用那就亏大了。 官方插件库 https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins 官方插件库并不一定有所有的插件&#xff0c;比如zsh-autosuggestions插件就不再列表里&#xff0c;下面演示zs…...

bypass hcaptcha、hcaptcha逆向

可以过steam&#xff0c;已支持并发&#xff0c;欢迎询问&#xff01; 有事危&#xff0c;ProfessorLuoMing...

python-UnitTest框架笔记

UnitTest框架的基本使用方法 UnitTest框架介绍 框架&#xff1a;framework&#xff0c;为了解决一类事情的功能集合 UnitTest框架&#xff1a;是python自带的单元测试框架 自带的&#xff0c;可以直接使用&#xff0c;不需要格外安装 测试人员用来做自动化测试&#xff0c;作…...

掌握API和控制点(从Java到JNI接口)_35 JNI开发与NDK 03

3、 如何载入 .so档案 VM的角色 由于Android的应用层级类别都是以Java撰写的&#xff0c;这些Java类别转译为Dex型式的Bytecode之后&#xff0c;必须仰赖Dalvik虚拟机器(VM: Virtual Machine)来执行之。 VM在Android平台里&#xff0c;扮演很重要的角色。此外&#xff0c;在执…...

计算机组成原理——存储系统(二)

&#x1f331; "人生最深的裂痕&#xff0c;往往是光照进来的地方。 别怕脚下的荆棘&#xff0c;那是你与平庸划清界限的勋章&#xff1b;别惧眼前的迷雾&#xff0c;星辰永远藏在云层之上。真正的强者不是从未跌倒&#xff0c;而是把每一次踉跄都踏成攀登的阶梯。记住&am…...

CDDIS从2025年2月开始数据迁移

CDDIS 将从 2025 年 2 月开始将我们的网站从 cddis.nasa.gov 迁移到 earthdata.nasa.gov&#xff0c;并于 2025 年 6 月结束。 期间可能对GAMIT联网数据下载造成影响。...

VSCode设置内容字体大小

1、打开VSCode软件&#xff0c;点击左下角的“图标”&#xff0c;选择“Setting”。 在命令面板中的Font Size处选择适合自己的字体大小。 2、对比Font Size值为14与20下的字体大小。...

嵌入式学习---蜂鸣器篇

1. 蜂鸣器分类 蜂鸣器是一种电子发声器件&#xff0c;采用直流电压供电&#xff0c;能够发出声音。广泛应用于计算机、打印机、报警器、电子玩具等电子产品中作为发声部件。一般仅从外形不易分辨蜂鸣器的种类。但是有些蜂鸣器使用广泛&#xff0c;见得多了就很容易分辨。例如常…...

【优先算法】专题——前缀和

目录 一、【模版】前缀和 参考代码&#xff1a; 二、【模版】 二维前缀和 参考代码&#xff1a; 三、寻找数组的中心下标 参考代码&#xff1a; 四、除自身以外数组的乘积 参考代码&#xff1a; 五、和为K的子数组 参考代码&#xff1a; 六、和可被K整除的子数组 参…...

【Linux】使用管道实现一个简易版本的进程池

文章目录 使用管道实现一个简易版本的进程池流程图代码makefileTask.hppProcessPool.cc 程序流程&#xff1a; 使用管道实现一个简易版本的进程池 流程图 代码 makefile ProcessPool:ProcessPool.ccg -o $ $^ -g -stdc11 .PHONY:clean clean:rm -f ProcessPoolTask.hpp #pr…...

使用Express.js和SQLite3构建简单TODO应用的后端API

使用Express.js和SQLite3构建简单TODO应用的后端API 引言环境准备代码解析1. 导入必要的模块2. 创建Express应用实例3. 设置数据库连接4. 初始化数据库表5. 配置中间件6. 定义数据接口7. 定义路由7.1 获取所有TODO项7.2 创建TODO项7.3 更新TODO项7.4 删除TODO项 8. 启动服务器 …...

Vue3 表单:全面解析与最佳实践

Vue3 表单&#xff1a;全面解析与最佳实践 引言 随着前端技术的发展&#xff0c;Vue.js 已经成为最受欢迎的前端框架之一。Vue3 作为 Vue.js 的最新版本&#xff0c;带来了许多改进和新的特性。其中&#xff0c;表单处理是 Vue 应用中不可或缺的一部分。本文将全面解析 Vue3 …...

找不到msvcp140.dll解决方法

您可以尝试以下方案进行修复&#xff0c;看看是否可以解决这个问题&#xff1a; 一、重新注册 msvcp140.dll 运行库文件&#xff1a; “WinR”打开运行&#xff0c;键入&#xff1a;regsvr32 MSVCP140.dll&#xff0c;回车即可&#xff1b; 如果出现找不到该文件的提示&…...