硬核手搓解析!进程-内核分析:命令行参数及环境变量,重构main()

目录

命令行参数与环境变量

命令行参数

vim下的main()

环境变量

环境变量的应用举例

查询环境变量

全部查询

针对名称查询(常用的方式)

环境变量的更改

配置环境变量

进程:命令行参数及环境变量的关系

结论

获取环境变量

①getenv();

②environ();

本地变量

特性:

本地变量的删除:

本地变量->环境变量:

问题探讨(内建命令)

库函数与系统调用


重构了main()函数-参数、运行环境,基于Linux进程深度下的吐血整理~~

命令行参数与环境变量

命令行参数

一个命令可以通过 [选项] 来实现特定的功能。

像:ls -a 及ls -a -l

类似于以前使用的main()函数中你可能见过的l两种形态:

cpp 复制代码
int main(int argc, char *argv[]);
int main(int argc, char **argv);

main()作为程序的入口,实际上我们也可以通过外部指定[选项]来传入并调用特定功能:

vim下的main()

vim内:

cpp 复制代码
int main(int argc, char *argv[])
{
    //......
    return 0;
}

在bash:

bash 复制代码
# 执行命令
./a.out -l -a hello world 123

本质就是将"-l -a hello world 123"分别分割并传入argv[]

|-----------|----------------------|
| argc | 5 |
| argv[0] | "./myprogram"(程序名) |
| argv[1] | "-l" |
| argv[2] | "-a" |
| argv[3] | "hello" |
| argv[4] | "world" |
| argv[5] | "123" |
| argv[6] | NULL(结束标志) |

运行代码:

cpp 复制代码
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("参数个数: %d\n", argc);
    
    for (int i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    
    return 0;
}

makefile内:

cpp 复制代码
  1 SRC=$(wildcard *.c)
  2 OBJ=$(SRC:.c=.o)
  3 CC=gcc -std=c99                                                                                                                 
  4 LFLAGS=-o
  5 FLAGS=-c
  6 RM=rm -f
  7 all:$(OBJ)
  8     $(CC) $^ $(LFLAGS) pc
  9 %.o:%.c
 10     $(CC) $(FLAGS) $< $(LFLAGS) $@
 11 .PHONY: clean
 12 clean:
 13     $(RM) pc $(OBJ)

运行:

环境变量

功能:环境变量是进程级[背景]配置。

|------|---------------------|
| 特性 | 说明 |
| 本质 | 键值对(HOME=/home/wzb) |
| 作用 | 配置环境运行环境,无需修改代码 |
| 继承性 | 子进程自动继承父进程的环境变量 |
| 作用范围 | 当前进程及其子进程 |

因此:环境变量具有全局特性,可被**++所有进程++ 继承**。

"进程级"配置又是一位程序新引入的执行逻辑,大大增加代码的复杂度。就像C中引入条件语句一般,是跨越性进步。

环境变量的应用举例

查询环境变量

全部查询

env

会打印显示全部已配置环境变量:

格式为[环境变量名称]=[环境变量内容]

针对名称查询(常用的方式)

echo \[名称\] #例如:echo PATH

环境变量的更改

①[原名称]=[新的绝对路径] #覆盖原路径

②[原名称]=$[原名称]:[拼接路径] #简便地路径拼接

配置环境变量

增加环境变量:

export [名称]=[内容]

删除环境变量:

unset [名称]

进程:命令行参数及环境变量的关系

无需多言:

我们在VS2022下运行

cpp 复制代码
#include<stdio.h>
int main(int argc, char* argv[], char* envp[])
{
	// envp是环境变量数组,格式为"KEY=val"
	for (char** env = envp; *env != NULL; env++)
	{
		printf("%s\n", *env);
	}
	return 0;
}

运行结果:

结果显而易见:环境变量全部显现。

结论

因此:自入进程开始我们就处于"命令行参数"+"环境变量"的配置环境。图示如下:

获取环境变量

①getenv();

头文件<stdlib.h>

函数原型:

cpp 复制代码
char* getenv(const char* name);

使用:

输入环境变量的名称来获取指向环境变量值的指针/NULL 。 // "指向目录路径"

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    char *path = getenv("PATH");
    char *home = getenv("HOME");

    printf("PATH: %s\n", path);
    printf("HOME: %s\n", home);
    
    return 0;
}

运行结果:

bash 复制代码
PATH: /usr/local/bin:/usr/bin:/bin
HOME: /home/wzb
②environ();

头文件:<stdlib.h>

函数原型:

cpp 复制代码
extern char** environ;

二级指针型访问数据可使用下标直接访问

代码实现:

输出同样的结果:


本地变量

本地变量是定义于vim外bash内的变量。

特性:

不会被子进程继承。

定义时"="++两侧不能加空格++ #否则会被当做命令进行查询 像:i=10正确而i = 10就是错误的!!

本地变量的删除:

像环境变量一样:

unset [本地变量名]

本地变量->环境变量:

export [本地变量名称]

问题探讨(内建命令)

众所周知:Linux指令是bash进程下执行文件的子进程。

假如export指令是一般性指令,怎么做到的子进程指令处理内容到父进程呢?

实际上:export别于一般性指令,其本质是"内建命令"(build-in command)。

++其不需要创建子进程,而是让bash自己操作++。

库函数与系统调用

指令"man"的指定页查询:

|-------|---------------|---------------------------------|
| 1 | 用户命令(可执行程序) | ls, cd, grep, find |
| 2 | 系统调用(内核提供的接口) | read, write, open, fork |
| 3 | 库函数(C 标准库) | printf, malloc, strcpy |

库函数与系统调用的对比

维度 系统调用 库函数
运行空间 内核态(Kernel Mode) 用户态(User Mode)
调用开销 大(需上下文切换) 小(普通函数调用)
实现者 操作系统内核 语言库(如 glibc)或应用程序
例子 read()write()open()fork() printf()scanf()fread()strcpy()
是否缓冲 无缓冲(直接操作内核) 通常有缓冲(如 stdio 缓冲)
执行速度

博主吐血回顾重构整理 求关注
o(╥﹏╥)o

相关推荐
星夜夏空991 小时前
STM32单片机学习(11)——GPIO输入实验
stm32·单片机·学习
YYYing.1 小时前
【C++项目之高并发内存池 (五)】一些小细节和性能优化及整体测试
c++·性能优化·高并发·内存池·基数树
青天喵喵1 小时前
Linux WiFi 架构解析:从用户态到驱动与硬件(基础篇)
linux·运维·arm开发·架构·wifi·嵌入式
毋语天1 小时前
Claude Code 完整安装与配置指南(含 CC-Switch 多供应商切换工具)
后端·python·ai编程
剑神一笑1 小时前
Linux watch 命令深度解析:从实时监控到变化检测的完整实现
linux·运维·服务器
StackNoOverflow1 小时前
RabbitMQ 入门详解(含安装 + 配置 + 管理后台)
开发语言·后端·ruby
2301_789015621 小时前
Linux:基础指令(二)
linux·运维·服务器·c语言·开发语言·c++·算法
燕-孑1 小时前
Shell脚本运维知识
运维