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