Согласно cppreference.com, getenv_s поддерживается с C11
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 ++, по-видимому, не представляет C11 от Microsoft ucrt? getenv_s?
В С ++ у нас уже есть портативный способ получения переменных среды безопасно?
Редактировать:
Первоначально исправленный ответ ниже не совсем корректен. В настоящее время нет декларации для getenv_s
в <sec_api/stdlib_s.h>
на реализациях MinGW-w64, но вы можете объявить это самостоятельно:
#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
там объявлено
Есть также несколько других шаблонных функций C ++, отсутствующих в <sec_api/stdlib_s.h>
уже, вероятно, из-за отсутствия необходимости и отсутствия декларации getenv_s
может быть, это просто то, что никому не нужно getenv
работал просто отлично.
Стоит отметить, что есть только для Windows функция называется _dupenv_s
это гораздо проще использовать вместо getenv_s
и вы просто освободите память, используя стандартную free
функция. Объявлено в <sec_api/stdlib_s.h>
, так что вы можете использовать его без проблем.
Измененный оригинальный ответ:
Во время этого ответа MinGW-w64, созданный из исходного кода, позволяет вам включать или отключать доступ к защищенным функциям CRT по умолчанию, но даже если он включен, он не помечает большинство стандартных функций C с безопасными заменами как «устаревшие» «То, как это делают заголовки CRT в Visual C ++ (на самом деле, кажется, что некоторые из них помечаются как устаревшие, но макросы расширяются до нуля в сборке, которую я использую).
Чтобы более прямо ответить на этот вопрос, реализация MinGW-w64 в настоящее время хранит прототипы для функций безопасной CRT в отдельном заголовочном файле в sec_api
каталог, и этот файл заголовка не включен из стандартного заголовка C, что означает соответствующий заголовок C ++ <cstdlib>
также не будет объявлять функции, поскольку включает только стандартный заголовок.
Вместо этого вам нужно явно включить нужные вам заголовки C, такие как <sec_api/stdlib_s.h>
, <sec_api/stdio_s.h>
и т. д., которые будут объявлять функции только в том случае, если включен безопасный API (т.е. MINGW_HAS_SECURE_API
определяется до 1 в _mingw.h
). Поскольку функции, вероятно, доступны для связывания, вы можете просто использовать #define MINGW_HAS_SECURE_API 1
перед включением, чтобы разрешить использование объявленных безопасных функций или объявить функции самостоятельно в случае, если они не объявлены.
Я чувствую, что стоит упомянуть, что многие, хотя и не все, C ++ — только шаблонные функции, такие как
// #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
);
объявлены и реализованы.
На основе примеры в документации Microsoft и вывод препроцессора в случае MinGW-w64, обе реализации помещают защищенные функции в глобальное пространство имен C ++, а не в std
пространство имен (например, strcpy_s
в его полностью квалифицированной форме ::strcpy_s
) поскольку они не являются стандартными функциями C ++.
В 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
это улучшение getenv
в C, где вам нужно как-то иметь дело с нулевыми указателями и длинами строк, в то время как в C ++ у нас есть различные доступные решения (std::string
для строк переменной длины и std::optional
для необязательных значений).