MinGW-w64 g ++是否公开Microsoft ucrt对C11`getenv_s`函数的实现?如果是,将包含什么标题?

时间:2018-08-18 05:34:30

标签: c++ mingw c++17 mingw-w64 c11

根据cppreference.com,自C11起,getenv_s得到支持

errno_t getenv_s( size_t *restrict len, char *restrict value,
                  rsize_t valuesz, const char *restrict name );

对于MinGW-w64 8.1,g ++报告#includecstdlibstdlib.h的错误

use of undeclared identifier 'getenv_s'; did you mean '_wgetenv_s'?
    errcode = getenv_s(&envsize, NULL, 0, name);
              ^~~~~~~~
              _wgetenv_s

我想知道为什么MinGW-w64 g ++似乎不公开Microsoft ucrt的C11 getenv_s吗?

在c ++中,我们是否已经有了 便携式 的方法来安全地检索环境变量?

2 个答案:

答案 0 :(得分:3)

  

在c ++中,我们是否已经有了一种可移植的方法来安全地检索环境变量?

您可以使用getenv。如果不想让指向别人的C字符串的原始指针泄漏到您的代码中,则可以使用std::optional

#include <cstdlib>
#include <optional>
std::optional<std::string> get_env(const char* env) {
    auto t = std::getenv(env);
    if (t) return t;
    return {};
}

Full example

PS:即使它在C ++中可用,也不确定是否要使用getenv_sresitrct不是标准的C ++,并且传递数组及其大小并不是非常习惯的C ++。据我了解,getenv_s是对C语言getenv的改进,在C语言中您需要以某种方式处理空指针和字符串长度,而在C ++中,我们有不同的解决方案(std::string用于可变长度字符串和{ {1}}(可选值)。

答案 1 :(得分:1)

编辑:

下面最初修改的答案并不完全正确。目前在MinGW-w64实现中,getenv_s中没有<sec_api/stdlib_s.h>的声明,但是您可以自己声明:

#ifdef __cplusplus
extern "C" {
#endif

#include <sec_api/stdlib_s.h> /* errno_t, size_t */
errno_t getenv_s(
    size_t     *ret_required_buf_size,
    char       *buf,
    size_t      buf_size_in_bytes,
    const char *name
);

/*
 * You can omit this section if you don't want to use the safer
 * C++ template function in your C++ code.
 */
#ifdef __cplusplus
extern "C++" {
  template <size_t size>
  getenv_s(
      size_t *ret_required_buf_size,
      char (&buf)[size],
      const char *name
  ) { return getenv_s(ret_required_buf_size, buf, size, name); }
}
#endif

#ifdef __cplusplus
}
#endif

在MSVC上,您仍然只使用#include <stdlib.h>,因为在那里声明了getenv_s

<sec_api/stdlib_s.h>中还缺少其他几个C ++模板函数,可能是由于缺乏需要,而getenv_s完全没有声明的可能仅仅是{{1 }}效果很好。

值得一提的是,a Windows-only function called _dupenv_sgetenv更易于使用,您只需使用标准的getenv_s函数就可以释放内存。它是在free中声明的,因此您可以毫无问题地使用它。


修改后的原始答案:

在回答此问题时,默认情况下,从源构建的MinGW-w64允许您启用或禁用安全CRT功能的公开,但是即使启用,它似乎也不会用安全替代品标记大多数标准C功能。以Visual C ++的CRT标头的方式“已弃用”(实际上,似乎确实将其中一些标为已弃用,但宏在我正在使用的内部版本中扩展为空)。

为了更直接地解决这个问题,MinGW-w64实现当前将安全CRT功能的原型存储在<sec_api/stdlib_s.h>目录中的单独头文件中,并且该头文件不包含在标准C头中,这意味着相应的C ++头文件sec_api也不会声明函数,因为它仅包含标准头文件。

相反,您需要显式包含所需的C标头,例如<cstdlib><sec_api/stdlib_s.h>等,它们仅在启用了安全API的情况下才声明函数(即{{1 }}在<sec_api/stdio_s.h>中定义为1。由于这些功能很可能可用于链接,因此您可以在包含任何内容之前使用MINGW_HAS_SECURE_API来启用已声明的安全功能,或者在未声明的情况下自行声明功能。

我觉得值得一提的是,尽管不是全部,但很多C ++模板功能,例如

_mingw.h

被声明并实现。

在MinGW-w64的情况下,基于examples in Microsoft's documentation和预处理器输出,两种实现都将安全功能放置在全局C ++命名空间中,而不是#define MINGW_HAS_SECURE_API 1命名空间中(例如// #include <sec_api/string_s.h> in MinGW-w64. // #include <string.h> (C) or <cstring> (C++) in MSVC. template <size_t size> errno_t strcpy_s( char (&dest)[size], const char *src ); 完全合格的格式为std),因为它们不是标准的C ++函数。