Есть ли способ использовать fopen_s() с GCC или, по крайней мере, создать #define для этого?
-
19-09-2019 - |
Вопрос
Компилятор MSVC говорит , что fopen()
является устаревшим и рекомендует использовать fopen_s()
.
Есть ли какой-нибудь способ использовать fopen_s()
и при этом оставаться портативным?
Есть какие-нибудь идеи для #define
?
Решение
Корпорация Майкрософт *_s
функции непереносимы, я обычно использую эквивалентные функции C89 / C99 и отключаю предупреждения об устаревании (#define _CRT_SECURE_NO_DEPRECATE
).
Если вы настаиваете, вы можете использовать функцию адаптера (не обязательно макрос!), которая делегирует fopen()
на платформах, которые не имеют fopen_s()
, но вы должны быть осторожны при сопоставлении значений errno_t
код возврата от errno
.
errno_t fopen_s(FILE **f, const char *name, const char *mode) {
errno_t ret = 0;
assert(f);
*f = fopen(name, mode);
/* Can't be sure about 1-to-1 mapping of errno and MS' errno_t */
if (!*f)
ret = errno;
return ret;
}
Однако я не вижу, как fopen_s()
является ли какой-либо более безопасный, чем fopen()
, поэтому я обычно предпочитаю мобильность.
Другие советы
если вы используете C11, fopen_s
является стандартной библиотекой:
http://en.cppreference.com/w/c/io/fopen
в gcc
вам нужно использовать --std=C11
параметр.
В коде C / C ++,
#ifdef __unix
#define fopen_s(pFile,filename,mode) ((*(pFile))=fopen((filename),(mode)))==NULL
#endif
В Makefile
CFLAGS += -D'fopen_s(pFile,filename,mode)=((*(pFile))=fopen((filename),(mode)))==NULL'
Обратите внимание, что при успешном выполнении fopen_s возвращает 0, в то время как fopen возвращает ненулевой указатель на файл.Поэтому необходимо добавить "==NULL" в конец макроса, например:
if (fopen_s(&pFile,filename,"r")) perror("cannot open file");
Многие защищенные функции Microsoft включены в приложение K стандарта C11, но оно не пользуется широкой поддержкой, поэтому переносимость по-прежнему остается проблемой.Существует необходимость в повышении безопасности в некоторых приложениях;возможно, поддержка улучшится в будущем.
Я в прошлом, я сделал это вот так:
#define fopen_s(fp, fmt, mode) *(fp)=fopen( (fmt), (mode))
Макрос прост и прямолинейен, достаточно хорош для чего-то быстрого и грязного, но он не обеспечивает исключительное поведение fopen_s и не обеспечит безопасность реальной функции fopen_s.
Описанный выше функциональный подход @Alex B частично воспроизводит правильное поведение при сбое;он возвращает errno (= EINVAL).Его подход мог бы быть расширен еще больше, создав исключение недопустимого параметра чтобы более полно воспроизвести поведение fopen_s.
#define fopen_s(fp, fmt, mode) ({\
*(fp)=fopen( (fmt), (mode));\
(*(fp) ) ? 0:errno;\
})
В соответствии с https://en.cppreference.com/w/c/io/fopen можно включить функции *_s в стандартной библиотеке:
Как и во всех функциях с проверкой границ,
fopen_s
гарантированно будет доступен только в том случае, если__STDC_LIB_EXT1__
определяется реализацией, и если пользователь определяет__STDC_WANT_LIB_EXT1__
к целочисленной константе1
перед включением<stdio.h>
.