在 C++ 中获取环境变量

Jinku Hu 2023年1月30日 2021年1月22日
  1. 使用 std::getenv 函数访问 C++ 中的环境变量
  2. 使用自定义检查例程来验证有效的环境变量值
在 C++ 中获取环境变量

本文将介绍几种在 C++ 中获取环境变量的方法。

使用 std::getenv 函数访问 C++ 中的环境变量

getenv 是在 C 标准库中实现的符合 POSIX 标准的函数,可以在 C++ 源文件中使用 <cstdlib> 头文件导入。该函数将字符串作为唯一的参数,并搜索与之相等的环境变量名。

环境变量通常用大写字母表示,但 getenv 仍然要求参数字符串不能用小写字母,因为即使它在程序环境中定义了,也不会与变量名匹配。函数返回的是 char*类型,对应的变量值就存放在这个类型中。

注意,我们将 getenv 的返回值分配给 const char*变量,因为我们需要确保程序不会修改该位置,否则会导致未定义的行为。

#include <iostream>
#include <string>
#include <cstdlib>

using std::cout; using std::getenv;
using std::string; using std::cerr;
using std::endl;

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 <iostream>
#include <string>
#include <cstdlib>

using std::cout; using std::getenv;
using std::string; using std::cerr;
using std::endl;

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 <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>

using std::cout; using std::getenv;
using std::string; using std::cerr;
using std::endl; using std::find;

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);

}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn