在C ++中访问环境变量


73

我想$HOME在我正在编写的C ++程序中访问环境变量。如果我用C编写代码,我只会使用该getenv()函数,但是我想知道是否有更好的方法可以做到这一点。这是我到目前为止的代码:

std::string get_env_var( std::string const & key ) {                                 
    char * val;                                                                        
    val = getenv( key.c_str() );                                                       
    std::string retval = "";                                                           
    if (val != NULL) {                                                                 
        retval = val;                                                                    
    }                                                                                  
    return retval;                                                                        
}           

我应该使用getenv()C ++访问环境变量吗?有一点我可能会碰到的问题,只要一点点知识就可以避免?


1
我认为您打算返回retval。
Ferruccio

除了Ferruccio指出的错误外,这对我来说似乎是正确的。
悲伤

@grieve,对其进行了测试,它的确正确
SubMachine

Answers:


70

getenv()在C ++中使用没有任何问题。它由定义stdlib.h,或者,如果您更喜欢标准库的实现,则可以cstdlib通过std::名称空间(即std::getenv())包含和访问该函数。绝对没有错。实际上,如果您担心可移植性,则最好使用这两个版本。

如果您关心可移植性,并且正在使用托管C ++,则可以使用.NET等效项- System::Environment::GetEnvironmentVariable()。如果要使用Windows的非.NET等效项,则可以简单地使用GetEnvironmentVariable()Win32函数。


我敢于注意到std :: getenv()实际上不在std名称空间中,而是位于default(null)名称空间中。
特贝2012年

9
@shbk,在<stdlib.h>中定义了一个getenv()函数,该函数位于全局命名空间中,即您所引用的函数。在std名称空间的<cstdlib>中还定义了一个getenv()函数。
马特·戴维斯

实际上,这个答案表明,getenv()不应使用。
IInspectable '16

6
为了清楚起见,getenv()在创建进程时访问环境变量的快照。如果环境变量在过程的生命周期中getenv()发生更改,则不会看到这些更改。如果这是一个问题,请使用GetEnvironmentVariable()
马特·戴维斯

29

我只是将代码重构一点:

std::string getEnvVar( std::string const & key ) const
{
    char * val = getenv( key.c_str() );
    return val == NULL ? std::string("") : std::string(val);
}

2
很棒的解决方案。简单明了!
dustinrwh

这不是一个“很棒的解决方案,但是您无法区分缺少的环境变量和空的环境变量。”
einpoklum

@einpoklum我敢打赌,在大多数情况下,区分这两种情况并不是特别有用。一个健壮的程序应该同时检查这两种情况,并且在“空”情况下可能会与“未设置”情况做同样的事情。当然,在特定情况下,必须设置非常特定的环境变量,并且“设置为空”是有意义的,但是我敢打赌,这些情况很少见。
josaphatv

“我敢打赌,在大多数情况下,区分这两种情况并不是特别有用”。
einpoklum

19

为什么要在Windows中使用MSDN getenv的GetEnvironmentVariable :

getenv仅在运行时库可访问的数据结构上运行,而不在操作系统为该进程创建的环境“段”上运行。因此,使用envp参数作为main或wmain的程序可能会检索无效信息。

从MSDN GetEnvironment

此函数可以检索系统环境变量或用户环境变量。


2
这是关于MSDN中的getenv()的奇怪评论。知道其真正含义是什么(即这些差异可能是什么时候以及什么时候出现)?
Michael Burr

我不确定,但我建议在Windows上使用GetEnvironmentVariable。最好使用Win32 API。
Brian R. Bondy

5
这意味着在启动过程后,Genenv将无法访问使用SetEnvironmentVariable设置的环境变量。
Bob9630'1

4
听起来微软没有理会getenv()正确地实现标准功能。那可能不是一个准确的解释,但这就是它的伤口。
基思·汤普森

微软的getenv或多或少是全局_environ变量的包装器。该变量在过程启动时初始化。如果某个进程通过Windows API(例如,通过调用SetEnvironmentVariable)更新其环境,则这不会反映在CRT_environ变量中。真正的环境存储在过程环境块(PEB)中,只能通过Windows API进行访问。
IInspectable '16


1

@Vlad的答案版本带有一些错误检查,可将空值与缺失值区分开:

inline std::string get_env(const char* key) {
    if (key == nullptr) {
        throw std::invalid_argument("Null pointer passed as environment variable name");
    }
    if (*key == '\0') {
        throw std::invalid_argument("Value requested for the empty-name environment variable");
    }
    const char* ev_val = getenv(key);
    if (ev_val == nullptr) {
        throw std::runtime_error("Environment variable not defined");
    }
    return std::string(ev_val);
}

笔记:

  • 您也可以将上面对异常的使用替换为,std::optional<std::string>或将来将替换为std::expected(如果最终被标准化)。
  • 我在这里选择安全性而不是信息性,方法是不将密钥连接到异常的what-string中。如果您选择其他方法,请尝试key在合理的范围内限制从到的复制(例如100个字符?200个字符?),然后我还要检查这些字符是否可打印,并清理这些字符。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.