MSVC编译器提示fopen()
已过时,建议使用fopen_s()
。
有没有办法在保持可移植性的前提下使用fopen_s()
?
是否有#define
的解决方案?
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()
更加安全,因此通常我会选择可移植性。
在C/C++代码中,
#ifdef __unix
#define fopen_s(pFile,filename,mode) ((*(pFile))=fopen((filename),(mode)))==NULL
#endif
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");
fopen_s()
在fopen()
失败时返回errno
的部分。 - Toby Speightfopen_s()
和其他函数是可选的,根据K.2范围第1段:“本附录指定了一系列可选扩展……”实际上,截至2019年,只有微软实现了Annex K,而微软的实现被认为“不能被视为符合或可移植”的(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm)。 - Andrew Henle*_s
“安全”函数的问题。简而言之,它们是不可移植的,并且在任何实际使用中唯一的实现 - Microsoft的实现也是不符合标准的。 - Andrew Henle #define fopen_s(fp, fmt, mode) *(fp)=fopen( (fmt), (mode))
#define fopen_s(fp, fmt, mode) ({\
*(fp)=fopen( (fmt), (mode));\
(*(fp) ) ? 0:errno;\
})
与所有边界检查函数一样,只有在实现定义了__STDC_LIB_EXT1__并且用户在包含之前将__STDC_WANT_LIB_EXT1__定义为整数常量1时,才保证可以使用。
__STDC_LIB_EXT1__
时才可以使用此选项。大多数实现都没有定义它。 - Toby Speight