Linux-exec函数族和system函数

参考资料:《Linux环境编程:从应用到内核》

execve函数

execve函数接口如下:

 #include <unistd.h>
 
 int execve(const char *filename, char *const argv[],
        char *const envp[]);

参数:

  • 第一个参数:filename是可执行的新程序的路径名,可以是绝对路径,也可以是相对于当前工作目录的相对路径;
  • 第二个参数:字符串指针组成的数组,以NULL结束。argv[0]一般对应可执行文件的文件名,也就是filename中的basename(路径名最后一个/后面的部分)。当然如果argv[0]不遵循这个约定也无妨,因为execve可以从第一个参数获取到要执行文件的路径,只要不是NULL即可。
  • 第三个参数:与C语言的main函数中的第三个参数envp一样,也是字符串指针数组,以NULL结束,指针指向的字符串的格式为name=value。

一般来说,execve()函数总是紧随fork函数之后。父进程调用fork之后,子进程执行execve函数,抛弃父进程的程序段,和父进程分道扬镳,从此天各一方,各走各路。但是也可以不执行fork,单独调用execve函数:

返回值:

execve函数返回值是特殊的,如果失败,返回-1,但如果成功,永不返回。

所以无须检查execve的返回值,只要返回,就必然是-1。可以从errno判断出出错的原因。出错的可能性非常多,手册提供了19种不同的errno,罗列了22种失败的情景。很难记住,好在大部分都不常见,常见的情况有以下几种:

  • EACCESS:这个是我们最容易想到的,就是第一个参数filename,不是个普通文件,或者该文件没有赋予可执行的权限,或者目录结构中某一级目录不可搜索,或者文件所在的文件系统是以MS_NOEXEC标志挂载的。
  • ENOENT:文件不存在。
  • ETXTBSY:存在其他进程尝试修改filename所指代的文件。
  • ENOEXEC:这个错误其实是比较高端的一种错误了,文件存在,也可以执行,但是无法执行,比如说,Windows下的可执行程序,拿到Linux下,调用execve来执行,文件的格式不对,就会返回这种错误。
// 准备外部程序 main.cpp

#include <iostream>

int main(int argc, char* args[])
{
    if (argc < 3)
    {
        std::cout << "函数参数太少" << std::endl;

        return -1;
    }

    int a = std::stoi(args[1]);
    int b = std::stoi(args[2]);

    std::cout << "a + b = " << (a + b) << std::endl;

    return 0;
}
// 示例

// execve函数

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

// 执行外部程序main
void func1()
{
    // 为什么使用const char*,之后又转一次?
    // 这是因为 "./main"、"1"、"2"在C++中都是字符串字面值,属于const char*,如果赋值给char*,就会用警告
    // 所以用const char*接收,之后通过const_cast去除const属性。
    const char* args[] = { "./main", "1", "2", nullptr };

    if (execve(const_cast<char*>(args[0]), const_cast<char**>(args), nullptr) == -1)
    {
        perror("execve");
        exit(EXIT_FAILURE);
    }
}

// 在终端执行 pwd -L 命令
void func2()
{
    const char* args[] = { "/bin/pwd", "-L", nullptr };

    if (execve(const_cast<char*>(args[0]), const_cast<char**>(args), nullptr) == -1)
    {
        perror("execve");
        exit(EXIT_FAILURE);
    }
}

int main()
{
    func1();

    // func2();

    std::cout << "never get here" << std::endl;

    return 0;
}

在这里插入图片描述

func1()和func2()不能同时测试,因为execve函数永不返回,无法执行完func1(),再执行func2()。

可以看到,我们在func1()里使用execve函数调用外部程序main,输出结果也是正确。

exec家族

从内核的角度来说,提供execve系统调用就足够了,但是从应用层编程的角度来讲,execve函数就并不那么好使了:

  • 第一个参数必须是绝对路径或是相对于当前工作目录的相对路径。习惯在shell下工作的用户会觉得不太方便,因为日常工作都是写ls和mkdir之类命令的,没有人会写/bin/ls或/bin/mkdir。shell提供了环境变量PATH,即可执行程序的查找路径,对于位于查找路径里的可执行程序,我们不必写出完整的路径,很方便,而execve函数享受不到这个福利,因此使用不便。
  • execve函数的第三个参数是环境变量指针数组,用户使用execve编程时不得不自己负责环境变量,书写大量的“key=value”,但大部分情况下并不需要定制环境变量,只需要使用当前的环境变量即可。

正是为了提供相应的便利,所以用户层提供了6个函数,当然,这些函数本质上都是调用execve系统调用,只是使用的方法略有不同,代码如下:

#include <unistd.h>
extern char **environ;

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);

int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[],char *const envp[]);

上述6个函数分成上下两个半区。分类的依据是参数采用列表(l,表示list)还是数组(v,表示vector)。上半区采用列表,它们会罗列所有的参数,下半区采用数组。在每个半区之中,带p的表示可以使用环境变量PATH,带e的表示必须要自己维护环境变量,而不使用当前环境变量,

在这里插入图片描述

// 示例 返回值自行判断

char* const ps_argv[] = { "ps","-ax",NULL };
char* const ps_envp[] = { "PATH=/bin:/usr/bin","TERM=console",NULL };

execl("/bin/ps", "ps", "-ax", NULL);

/*带p的,可以使用环境变量PATH,无须写全路径*/
execlp("ps", "ps", "-ax", NULL);

/*带e的需要自己组拼环境变量*/
execle("/bin/ps", "ps", "-ax", NULL, ps_envp);

execv("/bin/ps", ps_argv);

/*带p的,可以使用环境变量PATH,无须写全路径*/
execvp("ps", ps_argv);

/*带e的需要自己组拼环境变量*/
execve("/bin/ps", ps_argv, ps_envp);

system函数

程序可以调用system函数,来执行任意的shell命令,可以使C程序很方便地调用其他语言编写的程序。

函数接口如下:

#include <stdlib.h>

int system(const char *command);

这里将需要执行的命令作为command参数,传给system函数,该函数就帮你执行该命令。

这样看来system最大的好处就在于使用方便。不需要自己来调用fork、exec和waitpid,也不需要自己处理错误,处理信号,方便省心。

但是system函数的缺点也是很明显的。首先是效率,使用system运行命令时,一般要创建两个进程,一个是shell进程,另外一个或多个是用于shell所执行的命令。如果对效率要求比较高,最好是自己直接调用fork和exec来执行既定的程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/523742.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB技巧:从cell阵列里面提取部分cell的元素(使用大括号和小括号的情况)

在MATLAB中&#xff0c;元胞cell在定义的时候用的是小括号&#xff0c;如&#xff1a; 定义cell a cell(1,6);得到的cell如下&#xff1a; 对cell赋值 赋值的时候需要用大括号&#xff1a; a{1,3} 2&#xff1b;则可得到&#xff1a; 提取 如果要提取a的第3项的内容…

Unity Meta Quest MR 开发(五):空间锚点

文章目录 &#x1f4d5;教程说明 此教程相关的详细教案&#xff0c;文档&#xff0c;思维导图和工程文件会放入 Spatial XR 社区。这是一个高质量 XR 开发者社区&#xff0c;博主目前在内担任 XR 开发的讲师。该社区提供专人答疑、完整进阶教程、从零到一项目孵化保姆服务&…

11.内建函数对象_算数、关系、逻辑仿函数

文章目录 算数仿函数代码工程运行结果 关系仿函数代码工程运行结果 逻辑仿函数代码工程运行结果 算数仿函数 需要添加#include<functional>头文件使用 代码工程 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<functional>using namespace…

PicGo + Gitee + VsCode - 搭建私人图床

文章目录 前言搭建图床VsCode 安装插件安装 PicGo准备 Gitee 图床测试 尾声 前言 本人是一个重度 vimer&#xff0c;并且喜欢客制化一些东西… Typora 固然好用&#xff0c;但不支持 vim…发现 vscode 中既可以使用 vim&#xff0c;也可以 md&#xff0c;用起来比较舒服.因此…

rsync 远程同步----------安全高效的异地备份策略

目录 一、rsync介绍 rsync和cp的区别 rsync和scp的区别 二、rsync同步方式 rsync备份的方式 三、配置rsync源服务器 ①本地复制 ②下行同步 ③上行同步 四、常用Rsync命令 五、配置源的两种表达方法 六、部署rsync下行同步 ①环境准备 ②配置rsync源服务器-------…

白盒测试-语句覆盖

​ 语句覆盖法是指设计适当数量的测试用例&#xff0c;使被测程序中的每条语句至少被执行一次。语句覆盖率的计算方法为&#xff1a; ​ 至少被执行一次的语句数量 / 程序中可执行的语句总数。 案例 ​ 为了清晰地比较几种逻辑覆盖法设计测试用例的异同&#xff0c;逻辑覆盖…

【前沿模型解析】潜在扩散模型 2-1 | 手撕感知图像压缩 基础块ResNet块

文章目录 1 残差结构回顾2 LDM结构中的残差结构设计2.1 组归一化GroupNorm层2.2 激活函数层2.3 卷积层2.4 dropout层 3 代码实现 1 残差结构回顾 残差结构应该是非常重要的基础块之一了&#xff0c;你肯定会在各种各样的网络模型结构里看到残差结构&#xff0c;他是非常强大的…

二叉搜索树、AVL树、红黑树

为者常成&#xff0c;行者常至 文章目录 二叉搜索树节点查找插入重头戏——删除叶子节点只有一个子节点有两个子节点 分析 平衡二叉搜索树右单旋左右双旋插入的四种情况左左右右左右右左插入操作 小结 红黑树 二叉搜索树 二叉搜索树就是在二叉树的基础上增加一些规则&#xff…

【LeetCode】排序数组——不一样的方式实现快排

目录 题目链接 颜色分类 算法原理 代码实现 排序数组 算法原理 代码实现 最小的k个数 算法原理 代码实现 题目链接 LeetCode链接&#xff1a;75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; LeetCode链接&#xff1a;912. 排序数组 - 力扣&#xff08;L…

【三十七】【算法分析与设计】STL 练习,凌波微步,栈和排序,吐泡泡,[HNOI2003]操作系统,优先队列自定义类型

凌波微步 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 时间限制&#xff1a;C/C 1 秒&#xff0c;其他语言 2 秒 空间限制&#xff1a;C/C 32768K&#xff0c;其他语言 65536K 64bit IO Format: %lld 题目描述 小 Z 的体型实在是太胖了&…

【论文复现|智能算法改进】改进猎人猎物优化算法在WSN覆盖中的应用

目录 1.算法原理2.改进点3.结果展示4.参考文献 1.算法原理 【智能算法】猎人猎物算法&#xff08;HPO&#xff09;原理及实现 【智能算法应用】猎人猎物优化算法&#xff08;HPO&#xff09;在WSN覆盖中的应用 2.改进点 差分进化 自适应α变异 全局最优引导的动态反向学…

中仕公考:2024年成人高考大专能考事业编吗?

关于2024年成人高考大专学历是否具备报考事业单位编制的资格&#xff0c;相关规定明确地指出&#xff0c;该学历符合国家认证标准&#xff0c;并可在学信网进行验证。持有成人高考大专学历的考生&#xff0c;在满足其他职位需求的条件下&#xff0c;是有资格参加事业编考试的。…

VIM支持C/C++/Verilog/SystemVerilog配置并支持Win/Linux环境的配置

作为一个芯片公司打杂人口&#xff0c;同时兼数字IC和软件&#xff0c;往往需要一个皮实耐打上天入地的编辑器… 一、先附上github路径&#xff0c;方便取走 git clone gitgithub.com:qqqw4549/vim_config_c_verilog.git 二、效果展示 支持ctrl]函数/模块跳转&#xff0c;支持…

书生·浦语大模型实战营之茴香豆:搭建你的 RAG 智能助理

书生浦语大模型实战营之茴香豆&#xff1a;搭建你的 RAG 智能助理 RAG&#xff08;Retrieval Augmented Generation&#xff09;技术&#xff0c;通过检索与用户输入相关的信息&#xff0c;并结合外部知识库来生成更准确、更丰富的回答。解决 LLMs 在处理知识密集型任务时可能遇…

学习CSS Flexbox 玩flexboxfroggy flexboxfroggy1-24关详解

欢迎来到Flexbox Froggy&#xff0c;这是一个通过编写CSS代码来帮助Froggy和朋友的游戏! justify-content 和 align-items 是两个用于控制 CSS Flexbox 布局的属性。 justify-content&#xff1a;该属性用于控制 Flexbox 容器中子项目在主轴&#xff08;水平方向&#xff09;…

C++算法 —— 位运算

一、基本的位运算操作 1.基础位运算操作符 << : 二进制位整体左移 >> : 二进制位整体右移 ~ : 按位取反 & &#xff1a; 按位与 | &#xff1a; 按位或 ^ : 按位异或 &#xff08;无进位相加&#xff09; 2.给一个数n&#xff0c;确定它的二进制表示中第…

聚类算法 | Kmeans:肘方法、Kmeans++、轮廓系数 | DBSCAN

目录 一. 聚类算法划分方式1. 划分式2. 层次式3. 基于密度4. 基于网络5. 基于模型 二. K-means算法1. K-means算法公式表达2. K-means算法流程3. Kmeans算法缺点3.1 肘方法3.2 k-means 算法3.2.1 k-means|| 算法 3.3 Mini Batch K-Means 算法 4. 聚类评估 三. DBSCAN算法1. DBS…

秋招学习数据库LeetCode刷题

数据库基本知识以前学过次数较多&#xff0c;今天看完一遍后都是可以理解的。直接刷Leetcode题吧 牛客上题库刷基础&#xff0c;Leetcode刷 写语句题(争取坚持每日2个sql语句题) 牛客&#xff1a;https://www.nowcoder.com/exam/intelligent?questionJobId10&tagId21015 L…

C#速览入门

C# & .NET C# 程序在 .NET 上运行&#xff0c;而 .NET 是名为公共语言运行时 (CLR) 的虚执行系统和一组类库。 CLR 是 Microsoft 对公共语言基础结构 (CLI) 国际标准的实现。 CLI 是创建执行和开发环境的基础&#xff0c;语言和库可以在其中无缝地协同工作。 用 C# 编写的…

私域必备神器来袭!朋友圈转发一键搞定!

在私域运营中&#xff0c;朋友圈的转发和管理是至关重要的环节。为了能够更好的管理和运营多个微信号的朋友圈&#xff0c;很多人都开始使用微信管理系统来辅助自己开展管理和运营工作。 接下来&#xff0c;就一起来看看微信管理系统的朋友圈管理功能吧&#xff01; 首先&…