为什么我不能使用fopen?

时间:2009-05-25 12:46:16

标签: c++ c deprecated tr24731

a previous question I asked about the so-called safe library deprecations的模具中,我发现自己同样感到困惑,为什么{@ 1}}应该被弃用。

该函数接受两个C字符串,并返回FILE * ptr,或者在失败时返回NULL。线程安全问题/字符串溢出问题在哪里?还是别的什么?

提前致谢

6 个答案:

答案 0 :(得分:46)

可以使用fopen()。说真的,不要在这里注意到微软,他们通过偏离ISO标准让程序员真正受到伤害。他们似乎认为编写代码的人在某种程度上是脑死亡的,并且在调用库函数之前不知道如何检查参数。

如果有人不愿意学习C编程的复杂性,他们真的没有做生意。他们应该转向更安全的语言。

这似乎只是微软开发商锁定供应商的另一次尝试(虽然他们不是唯一尝试它的人,所以我并没有特别指责他们)。我通常会添加:

#define _CRT_SECURE_NO_WARNINGS

(或命令行中的"-D"变体)对我的大多数项目来说,确保在编写完全有效的合法C代码时我不会被编译器困扰。

Microsoft在fopen_s()函数(文件编码,一个)中提供了额外的功能,并改变了返回的方式。这可能会使Windows程序员更好,但使代码本身不可移植。

如果您只是要为Windows编写代码,请务必使用它。我自己更喜欢在任何地方编译和运行我的代码的能力(尽可能少地改变)。


从C11开始,这些安全功能现在已成为标准的一部分,尽管是可选的。请仔细阅读附件K.

答案 1 :(得分:20)

有一份官方的ISO / IEC JTC1 / SC22 / WG14(C语言)技术报告 TR24731-1 (边界检查接口)及其基本原理:

还有针对TR24731-2(动态分配功能)的工作。

fopen_s()的陈述理由是:

  

6.5.2文件访问功能

     

创建文件时,fopen_sfreopen_s函数可以通过设置文件保护并以独占访问权限打开文件来保护文件免受未经授权的访问,从而提高安全性。

规范说:

6.5.2.1 fopen_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);

运行约束

streamptrfilenamemode都不是空指针。

如果存在运行时约束违规,fopen_s不会尝试打开文件。 此外,如果streamptr不是空指针,fopen_s会将*streamptr设置为 空指针。

描述

  

fopen_s函数打开文件,其名称是指向的字符串   filename,并将流与之关联。

     

模式字符串应如fopen所述,并添加模式开始   字符'w'或'a'前面可能有'u'字符,见下文:

     
      
  • uw截断为零长度或创建用于写入的文本文件,默认权限
  •   
  • ua追加;打开或创建文本文件,以便在文件结束时写入默认权限
  •   
  • uwb截断为零长度或创建用于写入的二进制文件,默认权限
  •   
  • uab追加;打开或创建二进制文件,以便在文件结束时写入,默认   权限
  •   
  • uw+截断为零长度或创建文本文件以进行更新,默认权限
  •   
  • ua+追加;打开或创建文本文件以进行更新,在文件结尾处写入,默认   权限
  •   
  • uw+buwb+截断为零长度或创建二进制文件以进行更新,默认   权限
  •   
  • ua+buab+追加;打开或创建二进制文件以进行更新,在文件末尾写入,   默认权限
  •   
     

在底层系统支持概念的情况下,为写入而打开的文件   应使用独占(也称为非共享)访问权限打开。如果文件正在   创建,并且模式字符串的第一个字符不是'u',在某种程度上   底层系统支持它,该文件应具有防止其他的文件权限   系统上的用户访问该文件。如果正在创建文件和第一个字符   模式字符串是'u',然后到文件关闭时,它应该有   系统默认文件访问权限 10)

     

如果文件已成功打开,则FILE指向streamptr的指针   将被设置为指向控制打开文件的对象的指针。否则,指针   <{1}}指向的FILE将被设置为空指针。

     

返回

     

如果streamptr函数打开文件,则返回零。如果它没有打开文件或如果   存在运行时约束违规,fopen_s返回非零值。

     

10)这些权限与fopen创建的文件相同。

答案 2 :(得分:8)

Microsoft已将fopen_s()函数添加到C运行时,与fopen()存在以下基本差异:

  • 如果打开文件进行写入(模式中指定的“w”或“a”),则打开文件以进行独占(非共享)访问(如果平台支持)。
  • 如果在带有“w”或“a”说明符的mode参数中使用“u”说明符,那么在文件关闭时,它将具有系统默认权限,供其他用户访问该文件(如果这是系统默认值,则可能无法访问。
  • 如果指定的“u”在这些情况下,则当文件关闭时(或之前)时,将设置文件的权限,以便其他用户无权访问文件。

基本上,这意味着默认情况下,应用程序写入的文件会受到其他用户的保护。

由于现有代码可能会破坏,他们没有对fopen()执行此操作。

Microsoft已选择弃用fopen()以鼓励Windows开发人员有意识地决定其应用程序使用的文件是否具有松散权限。

Jonathan Leffler's answerfopen_s()提供了建议的标准化语言。我添加了这个答案,希望明确理由。

答案 3 :(得分:2)

  

还是别的什么?

'fopen'使用的FILE结构的一些实现将文件描述符定义为'unsigned short'。这将使您最多同时打开255个文件,减去stdin,stdout和stderr。

虽然能够拥有255个打开文件的价值是有争议的,当然,当你有超过252 socket connections时,这个实现细节在Solaris 8平台上实现了!最初出现在我的应用程序中使用libcurl建立SSL连接的看似随机的失败原因是由此引起的,但它花了部署libcurl和openssl的调试版本并通过调试器脚本踩到客户以最终弄明白。< / p>

虽然它不完全是'fopen'的错误,但人们可以看到摆脱旧界面束缚的优点;弃用的选择可能基于与过时的实现保持二进制兼容性的痛苦。

答案 4 :(得分:1)

新版本parameter validation,而旧版本没有。{/ p>

有关详细信息,请参阅this SO thread

答案 5 :(得分:1)

线程安全。 fopen()使用全局变量errno,而fopen_s()替换返回errno_t并使用FILE**参数存储文件指针。