为什么我不能用fopen?

时间:2022-08-31 06:52:19

In the mold of a previous question I asked about the so-called safe library deprecations, I find myself similarly bemused as to why fopen() should be deprecated.

在我之前问过的关于所谓的安全库弃用的问题的模式中,我发现自己同样困惑于为什么要弃用fopen()。

The function takes two C strings, and returns a FILE* ptr, or NULL on failure. Where are the thread-safety problems / string overrun problems? Or is it something else?

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

Thanks in advance

谢谢提前

6 个解决方案

#1


20  

There is an official ISO/IEC JTC1/SC22/WG14 (C Language) technical report TR24731-1 (bounds checking interfaces) and its rationale available at:

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

There is also work towards TR24731-2 (dynamic allocation functions).

还有TR24731-2(动态分配函数)的工作。

The stated rationale for fopen_s() is:

fopen_s()声明的基本原理是:

6.5.2 File access functions

When creating a file, the fopen_s and freopen_s functions improve security by protecting the file from unauthorized access by setting its file protection and opening the file with exclusive access.

在创建文件时,fopen_s和freopen_s函数通过设置文件保护和打开具有独占访问权限的文件来保护文件免受未经授权的访问,从而提高安全性。

The specification says:

规范说:

6.5.2.1 The fopen_s function

Synopsis

#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);

Runtime-constraints

None of streamptr, filename, or mode shall be a null pointer.

任何streamptr、文件名或模式都不是空指针。

If there is a runtime-constraint violation, fopen_s does not attempt to open a file. Furthermore, if streamptr is not a null pointer, fopen_s sets *streamptr to the null pointer.

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

Description

The fopen_s function opens the file whose name is the string pointed to by filename, and associates a stream with it.

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

The mode string shall be as described for fopen, with the addition that modes starting with the character ’w’ or ’a’ may be preceded by the character ’u’, see below:

模式串应如fopen所描述的那样,加上以“w”或“a”开头的模式可能会以“u”开头,如下图所示:

  • uw truncate to zero length or create text file for writing, default permissions
  • uw截断为零长度或创建文本文件的写入,默认权限。
  • ua append; open or create text file for writing at end-of-file, default permissions
  • ua追加;打开或创建文本文件以在文件结束时,默认权限。
  • uwb truncate to zero length or create binary file for writing, default permissions
  • uwb截断为零长度或创建用于写入的二进制文件,默认权限。
  • uab append; open or create binary file for writing at end-of-file, default permissions
  • 阿拉巴马大学的添加;打开或创建二进制文件,以便在文件末尾(默认权限)写入
  • uw+ truncate to zero length or create text file for update, default permissions
  • uw+截断到零长度或创建文本文件进行更新,默认权限
  • ua+ append; open or create text file for update, writing at end-of-file, default permissions
  • ua +附加;打开或创建文本文件进行更新,在文件末尾写入,默认权限
  • uw+b or uwb+ truncate to zero length or create binary file for update, default permissions
  • uw+b或uwb+截断到零长度或创建二进制文件进行更新,默认权限
  • ua+b or uab+ append; open or create binary file for update, writing at end-of-file, default permissions
  • ua + b或uab +附加;打开或创建二进制文件进行更新,在文件结束时写入,默认权限。

To the extent that the underlying system supports the concepts, files opened for writing shall be opened with exclusive (also known as non-shared) access. If the file is being created, and the first character of the mode string is not ’u’, to the extent that the underlying system supports it, the file shall have a file permission that prevents other users on the system from accessing the file. If the file is being created and first character of the mode string is ’u’, then by the time the file has been closed, it shall have the system default file access permissions10).

在基础系统支持这些概念的范围内,为编写而打开的文件应该具有排他性(也称为非共享)访问。如果正在创建文件,并且模式字符串的第一个字符不是“u”,在底层系统支持的范围内,该文件应该具有阻止系统上其他用户访问该文件的文件权限。如果正在创建文件,模式字符串的第一个字符是“u”,那么当文件被关闭时,它将具有系统默认的文件访问权限10)。

If the file was opened successfully, then the pointer to FILE pointed to by streamptr will be set to the pointer to the object controlling the opened file. Otherwise, the pointer to FILE pointed to by streamptr will be set to a null pointer.

如果文件被成功打开,那么streamptr指向的文件指针将被设置为控制打开文件的对象的指针。否则,streamptr指向的文件指针将被设置为空指针。

Returns

返回

The fopen_s function returns zero if it opened the file. If it did not open the file or if there was a runtime-constraint violation, fopen_s returns a non-zero value.

如果打开文件,则fopen_s函数返回0。如果没有打开文件,或者存在运行时约束违反,则fopen_s返回一个非零值。

10) These are the same permissions that the file would have been created with by fopen.

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

#2


46  

You can use fopen(). Seriously, don't take any notice of Microsoft here, they're doing programmers a real disservice by deviating from the ISO standards . They seem to think that people writing code are somehow brain-dead and don't know how to check parameters before calling library functions.

您可以使用fopen()。认真地说,不要在这里注意微软,他们偏离了ISO标准,给程序员带来了很大的麻烦。他们似乎认为编写代码的人在某种程度上是脑死亡的,在调用库函数之前不知道如何检查参数。

If someone isn't willing to learn the intricacies of C programming, they really have no business doing it. They should move on to a safer language.

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

This appears to be just another attempt at vendor lock-in by Microsoft of developers (although they're not the only ones who try it, so I'm not specifically berating them). I usually add:

这似乎只是微软对开发人员进行厂商*的又一次尝试(尽管他们并不是唯一尝试的人,所以我并不是特别严厉地批评他们)。我通常添加:

#define _CRT_SECURE_NO_WARNINGS

(or the "-D" variant on the command line) to most of my projects to ensure I'm not bothered by the compiler when writing perfectly valid, legal C code.

(或命令行上的“-D”变体)到我的大多数项目,以确保在编写完全有效的、合法的C代码时,编译器不会打扰我。

Microsoft has provided extra functionality in the fopen_s() function (file encodings, for one) as well as changing how things are returned. This may make it better for Windows programmers but makes the code inherently unportable.

微软在fopen_s()函数中提供了额外的功能(比如文件编码),并更改了返回方式。这对Windows程序员来说可能更好,但却使代码本身不可移植。

If you're only ever going to code for Windows, by all means use it. I myself prefer the ability to compile and run my code anywhere (with as little change as possible).

如果您只需要为Windows编写代码,那么就一定要使用它。我个人更喜欢在任何地方编译和运行代码的能力(尽可能少的更改)。


As of C11, these safe functions are now a part of the standard, though optional. Look into Annex K for full details.

从C11开始,这些安全函数现在是标准的一部分,尽管是可选的。详见附件K。

#3


8  

The fopen_s() function has been added by Microsoft to the C runtime with the following fundamental differences from fopen():

微软将fopen_s()函数添加到C运行时中,与fopen()有以下基本区别:

  • if the file is opened for writing ("w" or "a" specified in the mode) then the file is opened for exclusive (non-shared) access (if the platform supports it).
  • 如果打开文件进行写入(在模式中指定为“w”或“a”),则打开文件进行独占(非共享)访问(如果平台支持)。
  • if the "u" specifier is used in the mode argument with the "w" or "a" specifiers, then by the time the file is closed, it will have system default permissions for others users to access the file (which may be no access if that's the system default).
  • 如果在模式参数中使用了“u”说明符和“w”或“a”说明符,那么在文件关闭时,它将具有系统默认权限,允许其他用户访问该文件(如果这是系统默认的权限,则可能无法访问该文件)。
  • if the "u" specified is not used in those cases, then when the file is closed (or before) the permissions for the file will be set such that other users will not have access to the file.
  • 如果在这些情况下不使用指定的“u”,那么当文件关闭(或之前)时,文件的权限将被设置为其他用户无法访问该文件。

Essentially it means that files the application writes are protected from other users by default.

本质上,它意味着应用程序所写的文件在默认情况下是受其他用户保护的。

They did not do this to fopen() due to the likelyhood that existing code would break.

由于现有代码可能会被破坏,所以他们没有对fopen()这样做。

Microsoft has chosen to deprecate fopen() to encourage developers for Windows to make conscious decisions about whether the files their applications use will have loose permissions or not.

微软选择弃用fopen()来鼓励Windows的开发人员有意识地决定他们的应用程序使用的文件是否具有松散的权限。

Jonathan Leffler's answer provides the proposed standardization language for fopen_s(). I added this answer hoping to make clear the rationale.

Jonathan Leffler的回答为fopen_s()提供了建议的标准化语言。我加了这个答案,希望能说明理由。

#4


2  

Or is it something else?

还是别的什么?

Some implementations of the FILE structure used by 'fopen' has the file descriptor defined as 'unsigned short'. This leaves you with a maximum of 255 simultaneously open files, minus stdin, stdout, and stderr.

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

While the value of being able to have 255 open files is debatable, of course, this implementation detail materializes on the Solaris 8 platform when you have more than 252 socket connections! What first appeared as a seemingly random failure to establish an SSL connection using libcurl in my application turned out to be caused by this, but it took deploying debug versions of libcurl and openssl and stepping the customer through debugger script to finally figure it out.

虽然能够拥有255个打开文件的值是有争议的,当然,当您拥有超过252套接字连接时,这个实现细节将在Solaris 8平台上实现!最初在我的应用程序中使用libcurl建立SSL连接时出现的看似随机的失败是由这个原因导致的,但是它需要部署libcurl和openssl的调试版本,并通过调试器脚本将客户引导到最终的解决方案中。

While it's not entirely the fault of 'fopen', one can see the virtues of throwing off the shackles of old interfaces; the choice to deprecate might be based on the pain of maintaining binary compatibility with an antiquated implementation.

虽然这并不完全是“fopen”的错误,但我们可以看到摆脱旧接口束缚的优点;弃用的选择可能是基于保持二进制兼容性和过时的实现的痛苦。

#5


1  

The new versions do parameter validation whereas the old ones didn't.

新版本进行参数验证,而旧版本没有。

See this SO thread for more information.

请查看此链接以获取更多信息。

#6


1  

Thread safety. fopen() uses a global variable, errno, while the fopen_s() replacement returns an errno_t and takes a FILE** argument to store the file pointer to.

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

#1


20  

There is an official ISO/IEC JTC1/SC22/WG14 (C Language) technical report TR24731-1 (bounds checking interfaces) and its rationale available at:

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

There is also work towards TR24731-2 (dynamic allocation functions).

还有TR24731-2(动态分配函数)的工作。

The stated rationale for fopen_s() is:

fopen_s()声明的基本原理是:

6.5.2 File access functions

When creating a file, the fopen_s and freopen_s functions improve security by protecting the file from unauthorized access by setting its file protection and opening the file with exclusive access.

在创建文件时,fopen_s和freopen_s函数通过设置文件保护和打开具有独占访问权限的文件来保护文件免受未经授权的访问,从而提高安全性。

The specification says:

规范说:

6.5.2.1 The fopen_s function

Synopsis

#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);

Runtime-constraints

None of streamptr, filename, or mode shall be a null pointer.

任何streamptr、文件名或模式都不是空指针。

If there is a runtime-constraint violation, fopen_s does not attempt to open a file. Furthermore, if streamptr is not a null pointer, fopen_s sets *streamptr to the null pointer.

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

Description

The fopen_s function opens the file whose name is the string pointed to by filename, and associates a stream with it.

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

The mode string shall be as described for fopen, with the addition that modes starting with the character ’w’ or ’a’ may be preceded by the character ’u’, see below:

模式串应如fopen所描述的那样,加上以“w”或“a”开头的模式可能会以“u”开头,如下图所示:

  • uw truncate to zero length or create text file for writing, default permissions
  • uw截断为零长度或创建文本文件的写入,默认权限。
  • ua append; open or create text file for writing at end-of-file, default permissions
  • ua追加;打开或创建文本文件以在文件结束时,默认权限。
  • uwb truncate to zero length or create binary file for writing, default permissions
  • uwb截断为零长度或创建用于写入的二进制文件,默认权限。
  • uab append; open or create binary file for writing at end-of-file, default permissions
  • 阿拉巴马大学的添加;打开或创建二进制文件,以便在文件末尾(默认权限)写入
  • uw+ truncate to zero length or create text file for update, default permissions
  • uw+截断到零长度或创建文本文件进行更新,默认权限
  • ua+ append; open or create text file for update, writing at end-of-file, default permissions
  • ua +附加;打开或创建文本文件进行更新,在文件末尾写入,默认权限
  • uw+b or uwb+ truncate to zero length or create binary file for update, default permissions
  • uw+b或uwb+截断到零长度或创建二进制文件进行更新,默认权限
  • ua+b or uab+ append; open or create binary file for update, writing at end-of-file, default permissions
  • ua + b或uab +附加;打开或创建二进制文件进行更新,在文件结束时写入,默认权限。

To the extent that the underlying system supports the concepts, files opened for writing shall be opened with exclusive (also known as non-shared) access. If the file is being created, and the first character of the mode string is not ’u’, to the extent that the underlying system supports it, the file shall have a file permission that prevents other users on the system from accessing the file. If the file is being created and first character of the mode string is ’u’, then by the time the file has been closed, it shall have the system default file access permissions10).

在基础系统支持这些概念的范围内,为编写而打开的文件应该具有排他性(也称为非共享)访问。如果正在创建文件,并且模式字符串的第一个字符不是“u”,在底层系统支持的范围内,该文件应该具有阻止系统上其他用户访问该文件的文件权限。如果正在创建文件,模式字符串的第一个字符是“u”,那么当文件被关闭时,它将具有系统默认的文件访问权限10)。

If the file was opened successfully, then the pointer to FILE pointed to by streamptr will be set to the pointer to the object controlling the opened file. Otherwise, the pointer to FILE pointed to by streamptr will be set to a null pointer.

如果文件被成功打开,那么streamptr指向的文件指针将被设置为控制打开文件的对象的指针。否则,streamptr指向的文件指针将被设置为空指针。

Returns

返回

The fopen_s function returns zero if it opened the file. If it did not open the file or if there was a runtime-constraint violation, fopen_s returns a non-zero value.

如果打开文件,则fopen_s函数返回0。如果没有打开文件,或者存在运行时约束违反,则fopen_s返回一个非零值。

10) These are the same permissions that the file would have been created with by fopen.

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

#2


46  

You can use fopen(). Seriously, don't take any notice of Microsoft here, they're doing programmers a real disservice by deviating from the ISO standards . They seem to think that people writing code are somehow brain-dead and don't know how to check parameters before calling library functions.

您可以使用fopen()。认真地说,不要在这里注意微软,他们偏离了ISO标准,给程序员带来了很大的麻烦。他们似乎认为编写代码的人在某种程度上是脑死亡的,在调用库函数之前不知道如何检查参数。

If someone isn't willing to learn the intricacies of C programming, they really have no business doing it. They should move on to a safer language.

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

This appears to be just another attempt at vendor lock-in by Microsoft of developers (although they're not the only ones who try it, so I'm not specifically berating them). I usually add:

这似乎只是微软对开发人员进行厂商*的又一次尝试(尽管他们并不是唯一尝试的人,所以我并不是特别严厉地批评他们)。我通常添加:

#define _CRT_SECURE_NO_WARNINGS

(or the "-D" variant on the command line) to most of my projects to ensure I'm not bothered by the compiler when writing perfectly valid, legal C code.

(或命令行上的“-D”变体)到我的大多数项目,以确保在编写完全有效的、合法的C代码时,编译器不会打扰我。

Microsoft has provided extra functionality in the fopen_s() function (file encodings, for one) as well as changing how things are returned. This may make it better for Windows programmers but makes the code inherently unportable.

微软在fopen_s()函数中提供了额外的功能(比如文件编码),并更改了返回方式。这对Windows程序员来说可能更好,但却使代码本身不可移植。

If you're only ever going to code for Windows, by all means use it. I myself prefer the ability to compile and run my code anywhere (with as little change as possible).

如果您只需要为Windows编写代码,那么就一定要使用它。我个人更喜欢在任何地方编译和运行代码的能力(尽可能少的更改)。


As of C11, these safe functions are now a part of the standard, though optional. Look into Annex K for full details.

从C11开始,这些安全函数现在是标准的一部分,尽管是可选的。详见附件K。

#3


8  

The fopen_s() function has been added by Microsoft to the C runtime with the following fundamental differences from fopen():

微软将fopen_s()函数添加到C运行时中,与fopen()有以下基本区别:

  • if the file is opened for writing ("w" or "a" specified in the mode) then the file is opened for exclusive (non-shared) access (if the platform supports it).
  • 如果打开文件进行写入(在模式中指定为“w”或“a”),则打开文件进行独占(非共享)访问(如果平台支持)。
  • if the "u" specifier is used in the mode argument with the "w" or "a" specifiers, then by the time the file is closed, it will have system default permissions for others users to access the file (which may be no access if that's the system default).
  • 如果在模式参数中使用了“u”说明符和“w”或“a”说明符,那么在文件关闭时,它将具有系统默认权限,允许其他用户访问该文件(如果这是系统默认的权限,则可能无法访问该文件)。
  • if the "u" specified is not used in those cases, then when the file is closed (or before) the permissions for the file will be set such that other users will not have access to the file.
  • 如果在这些情况下不使用指定的“u”,那么当文件关闭(或之前)时,文件的权限将被设置为其他用户无法访问该文件。

Essentially it means that files the application writes are protected from other users by default.

本质上,它意味着应用程序所写的文件在默认情况下是受其他用户保护的。

They did not do this to fopen() due to the likelyhood that existing code would break.

由于现有代码可能会被破坏,所以他们没有对fopen()这样做。

Microsoft has chosen to deprecate fopen() to encourage developers for Windows to make conscious decisions about whether the files their applications use will have loose permissions or not.

微软选择弃用fopen()来鼓励Windows的开发人员有意识地决定他们的应用程序使用的文件是否具有松散的权限。

Jonathan Leffler's answer provides the proposed standardization language for fopen_s(). I added this answer hoping to make clear the rationale.

Jonathan Leffler的回答为fopen_s()提供了建议的标准化语言。我加了这个答案,希望能说明理由。

#4


2  

Or is it something else?

还是别的什么?

Some implementations of the FILE structure used by 'fopen' has the file descriptor defined as 'unsigned short'. This leaves you with a maximum of 255 simultaneously open files, minus stdin, stdout, and stderr.

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

While the value of being able to have 255 open files is debatable, of course, this implementation detail materializes on the Solaris 8 platform when you have more than 252 socket connections! What first appeared as a seemingly random failure to establish an SSL connection using libcurl in my application turned out to be caused by this, but it took deploying debug versions of libcurl and openssl and stepping the customer through debugger script to finally figure it out.

虽然能够拥有255个打开文件的值是有争议的,当然,当您拥有超过252套接字连接时,这个实现细节将在Solaris 8平台上实现!最初在我的应用程序中使用libcurl建立SSL连接时出现的看似随机的失败是由这个原因导致的,但是它需要部署libcurl和openssl的调试版本,并通过调试器脚本将客户引导到最终的解决方案中。

While it's not entirely the fault of 'fopen', one can see the virtues of throwing off the shackles of old interfaces; the choice to deprecate might be based on the pain of maintaining binary compatibility with an antiquated implementation.

虽然这并不完全是“fopen”的错误,但我们可以看到摆脱旧接口束缚的优点;弃用的选择可能是基于保持二进制兼容性和过时的实现的痛苦。

#5


1  

The new versions do parameter validation whereas the old ones didn't.

新版本进行参数验证,而旧版本没有。

See this SO thread for more information.

请查看此链接以获取更多信息。

#6


1  

Thread safety. fopen() uses a global variable, errno, while the fopen_s() replacement returns an errno_t and takes a FILE** argument to store the file pointer to.

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