Компилятор MSVC говорит, что fopen()
устарел и рекомендует использовать fopen_s()
.
Есть ли способ использовать fopen_s()
и по-прежнему быть переносимым?
Любые идеи для #define
?
Компилятор MSVC говорит, что fopen()
устарел и рекомендует использовать fopen_s()
.
Есть ли способ использовать fopen_s()
и по-прежнему быть переносимым?
Любые идеи для #define
?
Функции Microsoft *_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/С++
#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 включены в Приложение К стандарта C11, но он широко не поддерживается, поэтому переносимость по-прежнему остается проблемой. В некоторых приложениях требуется повышенная безопасность; возможно, поддержка будет улучшаться в будущем.
В прошлом я сделал это так:
#define fopen_s(fp, fmt, mode) *(fp)=fopen( (fmt), (mode))
Макрос прост и прямолинейный, достаточно хорош для чего-то быстрого и грязного, но он не обеспечивает поведение исключений fopen_s и не гарантирует безопасность реальной функции fopen_s.
Приближение функции Alex B частично частично воспроизводит правильное поведение при отказе; он возвращает errno (= EINVAL). Его подход может быть расширен далее путем создания недопустимого исключения параметра для более полного воспроизведения поведения fopen_s.
Согласно https://en.cppreference.com/w/c/io/fopen можно включить функции * _s в стандартной библиотеке:
Как и для всех функций с
fopen_s
границ,fopen_s
гарантированно будет доступен только в том случае, если__STDC_LIB_EXT1__
определен реализацией и если пользователь определяет__STDC_WANT_LIB_EXT1__
для целочисленной константы1
перед включением<stdio.h>
.
#define fopen_s(fp, fmt, mode) ({\
*(fp)=fopen( (fmt), (mode));\
(*(fp) ) ? 0:errno;\
})