文章目录
- 3.1 方法一:通过 main 函数的第三个参数隐式获取
- 3.2 方法二:通过系统调用 API getenv定向获取
- 3.3 方法三:通过全局第三方指针environ显式获取
概要&序論
Hello大家好,我是此方。本文将带大家由浅入深地拆解 Linux 系统级编程中的核心基石:环境变量。我们将从 main 函数隐藏的命令行参数切入,进而深度剖析环境变量的底层指针数组结构、三大核心获取手段 。好,我们开始。
零、 概念补充:命令行参数
0.1 重新认识 main 函数
0.1.1main函数不是程序的开始
main函数不是开始,也许你的老师经常说“main函数是代码的开始。”但是这是对于程序员而言的。vim code.s我们打开汇编代码:
Linux上是这个start,Windows上是_crt_start,这个函数内部调用main函数的逻辑如下
_start{ int ret = 0; int arg_count=0; arg_count=3; if(arg_count == 0) ret = main(); else if(arg_count==2) ret = main(argc, argv); else ret =main(argc, argv, env);}
扫描我们写的main函数,通过词法分析和语法分析得到这个count值是多少 然后调用不同的main函数。
0.1.2main函数也有参数
在初学 C/C++ 编程时,我们接触最多的 main 函数通常是不带任何参数的。然而在 Linux 系统级编程中,真正的 main 函数其实是可以携带参数的。最常见的声明方式如下:
intmain(int argc, char *argv[]);
这两个参数在程序启动时由操作系统自动传递。其中,argc是一个整型变量,用来记录命令行参数的个数;而 argv则是一个指向字符指针数组的指针,用来存储具体的命令行参数字符串。有种写法要知道一下:
intmain(int argc, char *argv[], char *env[]){ (void)argc;//为什么这么写: 应用一下变量,取消告警, //你设置了但是没有用可能会发出警告 (void)argv; (void)env;}
0.2 命令行参数的切分与表结构
当我们在终端键入一个诸如 ls -a -b -c 的命令并按下回车时,终端解释器 bash 会首先拿到这一串完整的输入字符串。随后,bash 会以空格作为分隔符,将这个长字符串打散成数个子字符串。 这些被切分好的字符串会被填入一张表中。以输入 ./code a b c 为例,系统内部构建的指针数组结构如图所示:
char *argv[]:+---+ +----------------+| 0 | -->| "./code" |+---+ +----------------+| 1 | -->| "a" |+---+ +----------------+| 2 | -->| "b" |+---+ +----------------+| 3 | -->| "c" |+---+ +----------------+| 4 | -->| NULL |+---+ +----------------+
bash 在切分字符串并构建该数组时,会在数组的末尾强制追加一个 NULL 指针作为结束标记。此时,参数的总个数 argc 的值为 4。
通过这种设计,进程便能清晰地知道自己拥有这样一张命令行参数表。(这很重要,我们后面会总结)
0.3 命令行参数的应用演示
为什么要大费周章地把命令行参数传给 main 函数呢?其根本目的在于实现同一个程序的不同子功能。在 Linux 中,我们经常使用的 ls -a、ls -l 等,本质上都是通过解析命令行参数表来实现的。 以下是一段 C++ 的演示代码,展示了如何通过不同的选项让程序支持不同的子功能:
#include<iostream>#include<string>using namespace std;// 演示:如何遍历打印所有的命令行参数voidTest01(int _argc, char* _argv[]){ for (int i = 0; i < _argc; i++) { cout << _argv[i] << endl; }}// 演示:不同的功能是怎么通过命令行参数选项实现的voidTest02(int _argc, char* _argv[]){ if (_argc != 2) { cout << "输入错误!请重新输入" << endl; } else { string cmd = _argv[1]; if (cmd == "a") cout << "执行一号功能" << endl; if (cmd == "b") cout << "执行二号功能" << endl; if (cmd == "c") cout << "执行三号功能" << endl; }}intmain(int argc, char *argv[]){ // Test01(argc, argv); // 取消注释可查看参数遍历结果 Test02(argc, argv); return 0;}
通过这段代码可以直观地发现,./code 自身作为 _argv[0] 也是一个命令行参数。通过接收并判断 _argv[1] 传入的选项(如 a、b、c),程序就能够走向不同的分支,从而获得不同的子功能。
一、 引入环境变量
1.1基本概念
1.1.1环境变量的概念
- 环境变量(environment variables) —— 一般是指在操作系统中用来指定操作系统运行环境的一些参数。名称=内容形式
- 如: 我们在编写 C/C++ 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
1.1.2常见环境变量
- PATH
- HOME : 指定用户的主工作目录(即用户登陆到 Linux 系统中时,默认的目录)
- SHELL : 当前 Shell,它的值通常是
/bin/bash。
1.1.3怎么看环境变量
| |
|---|
echo i=0; while [ i; let i++; done012345678910[whb@bite-alicloud lesson15]i | |