根据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 ++报告#include
与cstdlib
和stdlib.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 ++中,我们是否已经有了 便携式 的方法来安全地检索环境变量?
答案 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 {};
}
PS:即使它在C ++中可用,也不确定是否要使用getenv_s
。 resitrct
不是标准的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_s
比getenv
更易于使用,您只需使用标准的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 ++函数。