在 C++ 中获取环境变量
本文将介绍几种在 C++ 中获取环境变量的方法。
使用 std::getenv
函数访问 C++ 中的环境变量
getenv
是在 C 标准库中实现的符合 POSIX 标准的函数,可以在 C++ 源文件中使用 <cstdlib>
头文件导入。该函数将字符串作为唯一的参数,并搜索与之相等的环境变量名。
环境变量通常用大写字母表示,但 getenv
仍然要求参数字符串不能用小写字母,因为即使它在程序环境中定义了,也不会与变量名匹配。函数返回的是 char*
类型,对应的变量值就存放在这个类型中。
注意,我们将 getenv
的返回值分配给 const char*
变量,因为我们需要确保程序不会修改该位置,否则会导致未定义的行为。
#include <cstdlib>
#include <iostream>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
using std::getenv;
using std::string;
const char *ENV_VAR = "HOME";
int main() {
const char *tmp = getenv("HOME");
string env_var(tmp ? tmp : "");
if (env_var.empty()) {
cerr << "[ERROR] No such variable found!" << endl;
exit(EXIT_FAILURE);
}
cout << "HOME : " << env_var << endl;
exit(EXIT_SUCCESS);
}
输出:
HOME : /home/username
同样重要的是不要将 getenv
函数返回的值直接传递给 std::string
构造函数,因为当 getenv
函数不能计算任何环境变量时,可能会抛出一个分段故障。
这个问题是在 std::string
构造函数代码的实现中引起的,它在下面调用了 std::char_traits::length()
函数。如果将 nullptr
作为参数传递给它,后一个函数将导致未定义的行为。因此,就出现了这样的情况:当找不到环境变量时,getenv
可以返回 nullptr
,如果我们把它传给 string
构造函数,就会形成错误的代码。
#include <cstdlib>
#include <iostream>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
using std::getenv;
using std::string;
const char *ENV_VAR = "HOME";
int main() {
// Erroneous
string env_var(getenv("HOME"));
if (env_var.empty()) {
cerr << "[ERROR] No such variable found!" << endl;
exit(EXIT_FAILURE);
}
cout << "HOME : " << env_var << endl;
exit(EXIT_SUCCESS);
}
使用自定义检查例程来验证有效的环境变量值
在访问环境变量时,最危险的陷阱之一是验证检索的值。请注意,这些变量可能被攻击者在我们的程序范围之外进行操作。因此,需要对这些值进行额外的消毒,以确保程序执行的正确和安全。
这些检查例程主要是依赖于程序的,应该针对每种情况进行不同的处理。在下面的例子中,我们演示了这样的情况:我们假设字符串值中不应该有任何空格,如果有,我们就提取第一个空格字符之前的子字符串。通过这种方式,我们回避了系统环境中任何不规则的输入值。注意,std::find
算法被用来搜索 string
中的字符,如果没有找到指定的 char
,它将返回 string::npos
。
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
using std::find;
using std::getenv;
using std::string;
const char *ENV_VAR = "HOME";
int main() {
const char *tmp = getenv(ENV_VAR);
string env_var(tmp ? tmp : "");
if (env_var.empty()) {
cerr << "[ERROR] No such variable found!" << endl;
exit(EXIT_FAILURE);
}
// Env Variable Value Sanitization
int pos = env_var.find(' ');
if (pos != string::npos) env_var = env_var.substr(0, pos);
cout << "HOME : " << env_var << endl;
exit(EXIT_SUCCESS);
}