在我之前提出的问题关于所谓的安全库弃用的基础上,我发现自己同样困惑为什么fopen()
应该被弃用。
该函数接受两个C字符串,并返回一个FILE*指针,或在失败时返回NULL。哪里存在线程安全问题/字符串溢出问题?还是其他原因?
提前感谢。
在我之前提出的问题关于所谓的安全库弃用的基础上,我发现自己同样困惑为什么fopen()
应该被弃用。
该函数接受两个C字符串,并返回一个FILE*指针,或在失败时返回NULL。哪里存在线程安全问题/字符串溢出问题?还是其他原因?
提前感谢。
您可以使用fopen()
。严肃地说,不要理会微软的建议,他们偏离了ISO标准,给程序员带来了真正的伤害。他们似乎认为编写代码的人都有点傻,不知道在调用库函数之前如何检查参数。
如果有人不愿意学习C编程的复杂性,那么他们就没有做这件事的业务。他们应该转向更安全的编程语言。
这似乎只是微软针对开发人员的另一种供应商锁定的尝试(虽然他们并不是唯一尝试的人,所以我不是在特别抨击他们)。我通常会添加:
#define _CRT_SECURE_NO_WARNINGS
为了确保我在编写完全有效的C代码时不受编译器干扰,我将"-D"
变体(或者命令行上的)添加到大多数项目中。
Microsoft在fopen_s()
函数中提供了额外的功能(比如文件编码),并更改了返回方式。这可能使它对于Windows程序员更好,但也让代码天生无法移植。
如果你只是编写Windows专用代码,那么可以使用它。但我个人更喜欢能够在任何地方编译和运行代码(尽可能少地进行更改)。
从C11开始,这些安全函数现在已经成为标准的一部分,但是可选的。请查看附录K以了解完整详情。
有一个官方的ISO/IEC JTC1/SC22/WG14(C语言)技术报告TR24731-1(边界检查接口)及其相关原理可在以下网址中找到:
还有针对TR24731-2(动态分配函数)的工作正在进行中。
fopen_s()
的规定理由是:
6.5.2 文件访问函数
当创建文件时,
fopen_s
和freopen_s
函数通过设置文件保护并使用独占访问来提高安全性,以防止未经授权的访问。
规范说明如下:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
errno_t fopen_s(FILE * restrict * restrict streamptr,
const char * restrict filename,
const char * restrict mode);
streamptr
、filename
或mode
中的任何一个都不得为null指针。
如果存在运行时约束条件违规,fopen_s
将不尝试打开文件。
此外,如果streamptr
不是null指针,则fopen_s
将*streamptr
设置为null指针。
fopen_s
函数打开以指向filename
的字符串命名的文件,并与之关联一个流。模式字符串应如
fopen
所述,但添加了以下以字符"w"或"a"开头的模式:
uw
截断为零长度或创建文本文件进行写入,默认权限ua
追加;在文件结尾处打开或创建文本文件以进行写入,默认权限uwb
截断为零长度或创建二进制文件进行写入,默认权限uab
追加;在文件结尾处打开或创建二进制文件以进行写入,默认权限uw+
截断长度为零或创建文本文件进行更新,默认权限ua+
追加;打开或创建文本文件以进行更新,在文件结尾处进行写入,默认权限uw+b
或uwb+
截断为零长度或创建二进制文件进行更新,默认权限ua+b
或uab+
追加;打开或创建二进制文件以进行更新,在文件结尾处进行写入,默认权限在底层系统支持这些概念的范围内,打开用于写入的文件应该具有独占(也称为非共享)访问权限。 如果正在创建文件,并且模式字符串的第一个字符不是'u',则在底层系统支持的范围内,文件应具有防止系统上的其他用户访问文件的文件权限。 如果正在创建文件并且模式字符串的第一个字符为“u”,则在关闭文件之前,它应具有系统默认的文件访问权限10)。
如果文件成功打开,则通过
streamptr
指向的FILE
指针将设置为控制已打开文件的对象的指针。 否则,通过streamptr
指向的FILE
指针将设置为null指针。返回值
fopen_s
函数如果成功打开文件,则返回零。 如果它没有打开文件或存在运行时约束条件违规,则fopen_s
将返回非零值。10) 这些权限与通过fopen创建文件时相同。
fopen_s()
函数,与fopen()
相比有以下基本区别:
实质上,这意味着应用程序编写的文件默认受到保护,不受其他用户的干扰。
他们没有对fopen()
这样做,因为现有代码可能会出现问题。
Microsoft选择弃用fopen()
,鼓励Windows开发人员自觉决定其应用程序使用的文件是否具有松散的权限。
Jonathan Leffler的答案提供了fopen_s()
的拟议标准化语言。我添加了这个答案,希望能清楚地说明原理。
或者是其它什么原因呢?
'fopen' 使用的 FILE 结构的某些实现将文件描述符定义为 'unsigned short'。这意味着你最多只能同时打开 255 个文件,其中还要减去 stdin、stdout 和 stderr。
当然,能够同时打开 255 个文件的价值是有争议的。然而,当你在 Solaris 8 平台上拥有超过 252 个 socket 连接时,这个实现细节会变得非常明显,具体情况可以参考这篇文章(英文)!在我的应用程序中,使用 libcurl 建立 SSL 连接时出现了看似随机的连接失败问题,但最后发现这是由于这个问题引起的。解决这个问题需要部署调试版本的 libcurl 和 openssl,并通过调试器脚本逐步解决问题。
虽然这并不完全是“fopen”的错,但我们可以看到抛弃旧接口的优点;放弃这种古老实现的二进制兼容性可能是选择废弃该接口的原因。
线程安全。 fopen()
使用全局变量 errno
,而 fopen_s()
替代品返回一个 errno_t
并接受一个 FILE**
参数来存储文件指针。