在 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