Linux系统编程(再论execve)

news2024/11/24 0:06:08

文章目录

  • 前言
  • 一、execve的第三个参数
  • 二、进程空间
  • 三、命令行参数规范
  • 四、optstring规则的扩展定义
  • 总结


前言

本篇文章我们继续来研究一下execve这个系统调用,上篇文章已经讲解了前两个参数的意义了,那么这篇文章就来讲解一下第三个参数的具体含义。

一、execve的第三个参数

execve函数的第三个参数 envp 是一个字符串数组,用于传递给新程序的环境变量。

环境变量是操作系统提供给程序的一组全局变量,用于存储与系统环境相关的配置和信息。例如,PATH 环境变量指定了可执行程序所在的路径,HOME 环境变量指定了当前用户的家目录等。程序可以通过读取环境变量来获取系统相关的配置信息以及自定义的参数。

envp 参数是一个空指针结尾的字符串数组,每个元素都是一个以 "key=value" 形式表示的环境变量设置。例如,envp 数组可以包含类似以下的元素:

envp[0] = "PATH=/usr/local/bin:/usr/bin:/bin"
envp[1] = "HOME=/home/user"
envp[2] = "LANG=en_US.UTF-8"
...
envp[n] = NULL

在程序加载执行时,新程序会继承这些环境变量的设置,并且可以通过读取它们来获取相应的环境信息。

需要注意的是,envp 数组的最后一个元素必须是 NULL,用于表示环境变量列表的结束。

使用 envp 参数,可以在调用 execve 函数时传递自定义的环境变量给新程序。这允许程序在不同的执行环境中获得不同的配置。通过修改或添加环境变量,可以对新程序的行为进行定制和调整。

例如,可以根据需要设置自定义的环境变量,然后将其作为 envp 参数传递给 execve 函数,使新程序能够感知和使用这些自定义的环境变量。这样,新程序就可以根据环境变量的设置来执行不同的逻辑或采取不同的配置。
总结:

execve 函数的第三个参数 envp 是一个字符串数组,用于传递给新程序的环境变量。它允许自定义和传递环境变量给新程序,以便在程序加载执行时进行配置和定制。

这里对程序进行改进:
fork.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#define EXE "test"

int main(void)
{
    int pid = 0;

    char* argv[3] = {EXE, "world", NULL};

    printf("begin\n");

    printf("now pid : %d\n", getpid());

    if((pid = fork()) != 0)
    {
        //父进程
    }
    else
    {
        //子进程
        execve(EXE, argv, argv);
    }
   

    printf("end\n");

    return 0;
}

test.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char** argv, char** envp)
{
    int i = 0;
    printf("argc :%d\n", argc);

    for(i = 0; i < argc; i++)
    {
        printf("argv[%d] : %s\n", i, argv[i]);
    }

    printf("Hello World current pid :%d\n", getpid());

    i = 0;

    while(envp[i])
    {
        printf("envp[%d] :%s\n", i, envp[i]);
        i++;
    }

    return 0;
}

运行结果:
在这里插入图片描述
由运行结果可以看出子进程环境变量由父进程传递过来。

二、进程空间

这一张图片描述了进程的空间概要情况:
在这里插入图片描述
验证:

#include <stdio.h>
#include <malloc.h>

static void Text(void)
{

}

int main(int argc, char** argv)
{
    int i = 0;
    int* p = (int*)malloc(4);
    static int uninitval;
    static int initval = 0;

    printf("argv[0] :%p\n", argv);//启动参数
    printf("i : %p\n", &i);//栈地址
    printf("p = %p\n", p);//堆地址
    printf("uninitval = %p\n", &uninitval);//未初始化变量
    printf("initval = %p\n", &initval);//初始化变量
    printf("Text = %p\n", Text);//代码段


    return 0;
}

运行结果:
在这里插入图片描述
根据运行结果可以印证上图的结果。

三、命令行参数规范

1.由选项,选项值,操作数组成

2.选项由短横线(-)开始,选项名必须是单个字母或数字字符

3.选项可以有选项值,选项与选项值之间可用空格分隔(-o test -otest)

4.如果多个选项均无选项值,可合而为一(-a-b -c-abc)

5.既不是选项,也不能作为选项值的参数是操作数

6.第一次出现的双横线(–)用于结束所有选项,后续参数为操作数

getopt函数讲解:

getopt 是一个用于解析命令行选项的函数,它是C语言中标准库 <unistd.h> 中提供的函数。

getopt 函数可以帮助程序解析命令行参数,并提供了一种方便的方式来处理选项和选项参数。它支持简化的单字符选项(短选项)以及长选项(长选项)的解析。

以下是 getopt 函数的常见参数和用法:

int getopt(int argc, char *const argv[], const char *optstring);

argc:命令行参数的数量,即 main 函数的参数 argc。

argv:命令行参数的数组,即 main 函数的参数 argv。

optstring:指定程序支持的选项字符串。

getopt 函数会迭代解析命令行参数,并返回下一个选项的字符。当解析完所有的选项后,getopt 函数返回 -1,表示解析完毕。

在循环中调用 getopt 函数,可以逐个获取命令行参数中的选项和选项参数。例如:

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

int main(int argc, char *argv[]) {
  int opt;

  while ((opt = getopt(argc, argv, "abc:")) != -1) {
    switch (opt) {
      case 'a':
        printf("Option -a is set\n");
        break;
      case 'b':
        printf("Option -b is set\n");
        break;
      case 'c':
        printf("Option -c is set, value: %s\n", optarg);
        break;
      case '?':
        fprintf(stderr, "Unknown option: %c\n", optopt);
        return 1;
      default:
        break;
    }
  }

  for (int i = optind; i < argc; i++) 
  {
  	//非选项参数
    printf("Non-option argument: %s\n", argv[i]);
  }
  
  return 0;
}

以上示例代码解析了以下几种命令行参数:

单字符选项:

-a:表示选项 -a 被设置。

-b:表示选项 -b 被设置。
带参数的选项:

-c value:表示选项 -c 被设置,并且其参数为 value。
非选项参数(操作数):

通过循环使用 getopt 函数,可以依次获取每个选项及其参数,并使用 switch 语句进行处理。同时,可以在 optind 后的循环中获取非选项参数(操作数),并进行相应的处理。

需要注意的是,选项字符串中的冒号(:)可以用来指示带有参数的选项。例如,"abc:" 表示选项 -c 将带有参数。在 switch 语句中,optarg 变量用于获取选项的参数。

总结:
getopt 函数是一个用于解析命令行选项的函数。它通过遍历命令行参数,逐个解析选项和选项参数,并提供了一种方便的方式来处理命令行选项。通过了解 getopt 函数的使用方法,可以编写灵活的命令行工具,支持选项的解析和处理。

四、optstring规则的扩展定义

1.+ :将 getopt 函数的错误消息输出到 stderr(标准错误流)而不是 stdout(标准输出流)。通常情况下,错误消息会被发送到 stdout。使用 + 标志可以将错误消息重定向到 stderr,这样可以将标准输出用于其他目的。

2.- :使 getopt 函数返回一个非选项参数(即不以 - 或 – 开头的参数),作为额外的非选项参数。通常情况下,getopt 函数只返回选项字符,而将其他所有参数视为非选项参数。使用 - 标志可以将非选项参数作为额外的返回结果。

3.: :表示该选项需要一个参数。如果一个选项需要一个参数,但未提供该参数,则 getopt 函数将返回特殊值 ‘:’,并在 optopt 中存储选项字符。

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

int main(int argc, char** argv)
{
    int opt = -1;

    while((opt = getopt(argc, argv, ":abc:")) != -1)
    {
        switch (opt)
        {
        case 'a':
            printf("Option -a is set\n");
            break;
        case 'b':
            printf("Option -b is set\n");
            break;
        case 'c':
            printf("Option -c is set, value: %s\n", optarg);
            break;
        case '?':
            printf("Unknow option: -%c\n", optopt);
            break;        
        default:
            break;
        }
    }

    for(int i = optind; i < argc; i++)
    {
        printf("Non-option argument: %s\n", argv[i]);
    }


    return 0;
}

修改代码加上+符号,取消输出错误信息:
运行结果:
在这里插入图片描述

总结

本篇文章就讲解到这里。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三分钟学习一个python小知识4-----------我的对python中numpy的理解, 我列举了关于numpy常用的10个例子来深入理解numpy

这里写目录标题 1、NumPy是什么2、NumPy的常见应用---必须掌握2.1.创建一个数组2.2.数组的属性2.3.取数组中的元素2.4.数组的运算2.5.数组的转置2.6. 数组的索引和切片2.7. 数组的重塑2.8. 数组的广播2.9. 数组的聚合操作2.10. 数组的排序 总结 1、NumPy是什么 NumPy是专门用于…

vue+elementui实现app布局小米商城,样式美观大方,功能完整

目录 一、项目效果在线预览 二、效果图 1.首页效果图 2.分类&#xff0c;动态分类商品数据根据所属分类动态切换 3.购物车&#xff0c;动态添加购物车&#xff08;增、删、改、查&#xff09; 4.我的 5.登录注册 6.商品详情 7.搜索&#xff08;动态模糊搜索、搜索历史…

12---整数转罗马数字

罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例…

文件上传漏洞-用骗子的角度分析

&#xff08;一&#xff09;文件上传漏洞 文件上传漏洞&#xff0c;发送在用户上传文件功能中&#xff0c;很多网址都对上传的文件格式进行限制&#xff0c;但是被攻击机者找到漏洞&#xff0c;把木马、病毒进行上传&#xff0c;然后控制服务器。对上传的文件格式不是不限制&a…

MySQL实战解析底层---为什么这些SQL语句逻辑相同,性能却差异巨大

目录 前言 案例一&#xff1a;条件字段函数操作 案例二&#xff1a;隐式类型转换 案例三&#xff1a;隐式字符编码转换 前言 在MySQL中&#xff0c;有很多看上去逻辑相同&#xff0c;但性能却差异巨大的SQL语句对这些语句使用不当的话&#xff0c;就会不经意间导致整个数据…

动态规划V (85、91、97)-最近都开始摆烂

CP85 最大矩形 题目描述&#xff1a; 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 学习记录&#xff1a; 对每一个地方都去统计最大举行的话&#xff0c;会有很多多余的计算&#xff0c;题…

windows操作系统线程结构体

上一篇我们介绍了进程结构体&#xff0c;这节我们介绍下线程结构体&#xff1a;ETHREAD。还是去windbg里面去看一下这个结构体的长相: 依旧是一大堆成员&#xff0c;我们只关注一些比较重要的结构体成员。在进程结构体中的第一个成员是一个子结构体Pcb,在线程结构体中&#xff…

【Simulink】基于FCS-MPC的带阻感负载的三相逆变器控制(Matlab Function)

之前写过三相并网逆变器FCS-MPC的博客 &#x1f449;【Simulink】基于FCS-MPC的三相并网逆变器控制&#xff08;Matlab Function&#xff09; 应用的对象是并网的&#xff0c;用一个电压源&#xff08;Three-Phase Programmable Voltage Source&#xff09;模拟交流电网。 本篇…

6.S081——设备中断与驱动部分(串口驱动与Console)——xv6源码完全解析系列(7)

0.briefly speaking 之前我们研究过Xv6中的陷阱机制&#xff0c;并搞懂了系统调用的全部流程&#xff0c;接下来我们以UART和console为研究对象&#xff0c;深入研读一下Xv6内核中有关设备中断驱动的代码&#xff0c;并对UART、shell、console、键盘、显示器等设备的协同运作过…

【算法总结】——排列型回溯

文章目录 排列型回溯例题1——46. 全排列例题2——N皇后 分析回溯时间复杂度的另一种技巧 排列型回溯 相比于组合&#xff0c;排列型回溯对于元素的顺序是有要求的。 为了告诉回溯下面还可以选择哪些数字&#xff0c;可以&#xff1a; 记录已经被选择的数字用一个集合存储还…

【Linux】16. 动静态库

1. 库概念的引出 但是如果只是单纯的将多个.o文件提供给使用者&#xff0c;那么如果.o文件过多链接就会变得非常复杂&#xff0c;于是我们考虑将所有的.o文件打包给使用者提供一个库文件即可。 库的本质就是.o文件的集合 2. 动静态库概念 在之前的学习过程中我们认识到动静态…

免费:5000个高清视频素材 (个人免费版权,含9个利基)

免费&#xff1a;5000个高清视频素材 (个人免费版权&#xff0c;含9个利基) 嘿&#xff01;你喜欢制作视频吗&#xff1f;总是在寻找一些酷炫的素材&#xff0c;但又担心会侵犯版权吗&#xff1f;别担心&#xff0c;我有一个超级好消息要告诉你&#xff01;现在&#xff0c;我…

代码随想录算法训练营第39天 | 62.不同路径 + 63.不同路径 II

今日任务 目录 62.不同路径 - Medium 63.不同路径 II - Medium 62.不同路径 - Medium 题目链接&#xff1a;力扣-62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器…

【数据结构】排序

插入排序 把当前遍历到的元素前的元素序列是排好序的,把当前元素放到前边的序列中进行排序。 直接插入排序 不带哨兵 void InsertSort(int A[],int n) { int i,j,temp; for(i1;i<n;i) if(A[i]<A[i-1]) { tempA[i]; for(ji-1;j>0 && A[j]>temp;--j) A[j…

深入理解深度学习——BERT派生模型:参数共享ALBERT

分类目录&#xff1a;《深入理解深度学习》总目录 预训练语言模型的一个趋势是使用更大的模型配合更多的数据&#xff0c;以达到“大力出奇迹”的效果。随着模型规模的持续增大&#xff0c;单块GPU已经无法容纳整个预训练语言模型。为了解决这个问题&#xff0c;谷歌提出了ALBE…

深度学习训练营之文本分类识别

深度学习训练营之文本分类识别 原文链接环境介绍前置工作设置环境设置GPU加载数据 构建词典生成数据批次和迭代器模型定义定义实例 定义训练函数和评估函数模型训练模型评估 原文链接 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考…

面具下的flag

打开文件是你的名字动漫的一张图片 用010打开文件&#xff0c;比较可疑的有三处 首先文件头是正确的&#xff0c;只是这边显示的Exif&#xff0c;之前没有特别注意jpg文件有这个头 其次是文件中包含两处flag信息&#xff0c;一个是类似隐藏的文件&#xff0c;一个疑似是第二段f…

Mysql高级查询语句

数据库是用来存储数据&#xff0c;更新&#xff0c;查询数据的工具&#xff0c;而查询数据是一个数据库最为核心的功能&#xff0c;数据库是用来承载信息&#xff0c;而信息是用来分析和查看的。所以掌握更为精细化的查询方式是很有必要的。本文将围绕数据的高级查询语句展开。…

题集-栈和队列的相互转化

这里&#xff0c;队列的性质是先入先出&#xff0c;但是栈的性质是后入先出。两个队列就可以通过相互捯实现数据的后入先出。 typedef int QDataType&#xff1b; //这是一个队列结点的结构 typedef struct QueueNode { struct QueueNode* next; QDataType data; }QNode; //这是…

C++之工厂模式

目录 一、为什么要使用工厂模式 优点 缺点 二、简单工厂&#xff08;Simple Factory&#xff09; 好处&#xff1a; 不足&#xff1a; 三、工厂方法&#xff1a; 好处&#xff1a; 不足&#xff1a; 四、抽象工厂&#xff08;Abstract Factory&#xff09; 一、为什…