MSVC compiler says that fopen()
is deprecated, and recommends the use of fopen_s()
.
Is there any way to use fopen_s()
and still be portable?
Any ideas for a #define
?
MSVC compiler says that fopen()
is deprecated, and recommends the use of fopen_s()
.
Is there any way to use fopen_s()
and still be portable?
Any ideas for a #define
?
Microsoft's *_s
functions are unportable, I usually use equivalent C89/C99 functions and disable deprecation warnings (#define _CRT_SECURE_NO_DEPRECATE
).
If you insist, you can use an adaptor function (not necessarily a macro!) that delegates fopen()
on platforms that don't have fopen_s()
, but you must be careful to map values of errno_t
return code from 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;
}
However, I fail to see how fopen_s()
is any more secure than fopen()
, so I usually go for portability.
if you are using C11, fopen_s
is a standard library:
http://en.cppreference.com/w/c/io/fopen
in gcc
you need to use --std=C11
parameter.
In C/C++ code,
#ifdef __unix
#define fopen_s(pFile,filename,mode) ((*(pFile))=fopen((filename),(mode)))==NULL
#endif
In Makefile
CFLAGS += -D'fopen_s(pFile,filename,mode)=((*(pFile))=fopen((filename),(mode)))==NULL'
Attention that on success fopen_s return 0 while fopen return a nonzero file pointer. Therefore it is necessary to add "==NULL" to the end of macro, e.g.:
if (fopen_s(&pFile,filename,"r")) perror("cannot open file");
Many of Microsoft's secure functions are included in Annex K of the C11 standard, but it is not widely supported, so portability is still an issue. There is a need for the improved security in some applications; maybe the support will improve in the future.
I the past, I did it like this:
#define fopen_s(fp, fmt, mode) *(fp)=fopen( (fmt), (mode))
The macro is simple and straight forward, good enough for something quick and dirty, but it doesn't provide the exception behavior of fopen_s, and it won't provide the security of the real fopen_s function.
@Alex B's function approach above partially reproduces the proper behavior on failure; he returns errno (= EINVAL). His approach could be extended further by generating an invalid parameter exception to more fully reproduce the behavior of fopen_s.
Accroding to https://en.cppreference.com/w/c/io/fopen it's possible to enable *_s functions on stdc library
"As with all bounds-checked functions, fopen_s is only guaranteed to be available if STDC_LIB_EXT1 is defined by the implementation and if the user defines STDC_WANT_LIB_EXT1 to the integer constant 1 before including stdio.h."