【问题标题】:Accessing Environment Variables In C++在 C++ 中访问环境变量
【发布时间】:2010-10-12 12:18:14
【问题描述】:

我想在我正在编写的 C++ 程序中访问 $HOME 环境变量。如果我用 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++ 中的环境变量吗?有没有一些我可能遇到的问题,我可以通过一点知识避免?

【问题讨论】:

  • 我认为你的意思是返回 retval。
  • 除了 Ferruccio 指出的错误之外,这在我看来是正确的。
  • @grieve,测试了一下,确实是对的

标签: c++ environment-variables


【解决方案1】:

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

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

【讨论】:

  • 我敢注意到 std::getenv() 实际上并不位于 std 命名空间中,而是位于 default(null) 命名空间中。
  • @shbk,在 中定义了一个 getenv() 函数,它位于全局命名空间中,也就是您所指的那个。在 std 命名空间中的 中还定义了一个 getenv() 函数。
  • 其实this answer建议不要使用getenv()。
  • 为清楚起见,getenv() 在创建进程时访问环境变量的快照。如果环境变量在进程的生命周期内发生变化,getenv() 将看不到这些变化。如果这是一个问题,请使用GetEnvironmentVariable()。
【解决方案2】:

我只是稍微重构一下代码:

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

【讨论】:

  • 很棒的解决方案。简洁明了!
  • 这不是一个“很棒的解决方案,但您无法区分缺少的环境变量和空的环境变量。
  • @einpoklum 我敢打赌,大多数时候区分这两种情况并不是特别有用。一个健壮的程序应该检查这两种情况,并且可能在“空”情况下和“未设置”情况下做同样的事情。当然,在某些特定情况下,必须设置一个非常特定的环境变量并且“设置为空”是有意义的,但我敢打赌,这些情况很少见。
  • “我敢打赌,在大多数情况下,区分这两种情况并不是特别有用”
【解决方案3】:

为什么在 Windows 中使用 GetEnvironmentVariable,from MSDN getenv:

getenv 只对数据进行操作 运行时可访问的结构 图书馆而不是环境 为流程创建的“段”由 操作系统。所以, 使用 envp 参数的程序 main 或 wmain 可能检索无效 信息。

还有from MSDN GetEnvironment:

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

【讨论】:

  • 这是来自 MSDN 的关于 getenv() 的奇怪评论。知道它的真正含义(即,这些差异可能是什么以及何时)?
  • 我不太清楚,但我建议在 Windows 上使用 GetEnvironmentVariable。使用 Win32 API 总是更好。
  • 这意味着使用 SetEnvironmentVariable 设置的环境变量在进程启动后无法访问 genenv。
  • 听起来微软没有费心去正确实现标准的getenv()函数。这可能不是一个准确的解释,但事实就是如此。
  • Microsoft 的 getenv 或多或少是对全局 _environ 变量的封装。该变量在进程启动时初始化。如果进程通过 Windows API 更新其环境(例如,通过调用 SetEnvironmentVariable),这不会反映在 CRT _environ 变量中。真实环境存储在进程环境块 (PEB) 中,只能通过 Windows API 访问。
【解决方案4】:

在 c++ 中你必须使用 std::getenv 和 #include <cstdlib>

【讨论】:

    【解决方案5】:

    @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 替换上述异常的使用(如果最终标准化的话)。
    • 我在这里选择了安全性而不是信息性,没有将密钥连接到异常的内容字符串中。如果您做出替代选择,请尝试将从 key 复制到合理范围内(例如 100 个字符?200 个字符?),我还会检查这些字符是否可打印,以及 sanitize 这些字符。

    【讨论】:

      【解决方案6】:

      是的,我知道这是一个旧线程!
      不过,根据定义,常见错误并不新鲜。 :-)

      我看到不只是使用 std::getenv() 的唯一原因是添加 known default 或在 framework 中采用通用模式/API .在这种情况下,我也会避免异常(虽然通常不是),因为非值返回通常足以对环境变量进行有效响应。增加处理异常的复杂性是违反直觉的。

      这基本上是我使用的:

      const char* GetEnv( const char* tag, const char* def=nullptr ) noexcept {
        const char* ret = std::getenv(tag);
        return ret ? ret : def; 
      }
          
      int main() {
        int ret=0;
        if( GetEnv("DEBUG_LOG") )  {
          // Setup debug-logging
        } else {
           ...
        }
        return (-1==ret?errno:0);
      }
      

      这个答案和其他答案之间的差异可能看起来很小,但我发现当你养成编码习惯时,这样的小细节是非常有益的。

      就像 getenv() 返回一个 non-const 指针一样,这很容易导致坏习惯!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-26
        • 1970-01-01
        • 2011-04-26
        • 1970-01-01
        相关资源
        最近更新 更多