C++ 为什么我不能使用 fopen?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/906599/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I use fopen?
提问by JamieH
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 字符串,并在失败时返回 FILE* ptr 或 NULL。线程安全问题/字符串溢出问题在哪里?或者是别的什么?
Thanks in advance
提前致谢
采纳答案by Jonathan Leffler
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
andfreopen_s
functions improve security by protecting the file from unauthorized access by setting its file protection and opening the file with exclusive access.
6.5.2 文件访问功能
创建文件时,
fopen_s
和freopen_s
函数通过设置文件保护并以独占访问权限打开文件来保护文件免受未经授权的访问来提高安全性。
The specification says:
规范说:
6.5.2.1 The fopen_s function
6.5.2.1 fopen_s 函数
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
,filename
或mode
将是一个空指针。
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 byfilename
, and associates a stream with it.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:
uw
truncate to zero length or create text file for writing, default permissionsua
append; open or create text file for writing at end-of-file, default permissionsuwb
truncate to zero length or create binary file for writing, default permissionsuab
append; open or create binary file for writing at end-of-file, default permissionsuw+
truncate to zero length or create text file for update, default permissionsua+
append; open or create text file for update, writing at end-of-file, default permissionsuw+b
oruwb+
truncate to zero length or create binary file for update, default permissionsua+b
oruab+
append; open or create binary file for update, writing at end-of-file, default permissionsTo 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).
If the file was opened successfully, then the pointer to
FILE
pointed to bystreamptr
will be set to the pointer to the object controlling the opened file. Otherwise, the pointer toFILE
pointed to bystreamptr
will be set to a null pointer.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.10)These are the same permissions that the file would have been created with by fopen.
该
fopen_s
函数打开名称为 指向的字符串的文件filename
,并将流与其关联。模式字符串应如 中所述
fopen
,此外,以字符 'w' 或 'a' 开头的模式可以在字符 'u' 之前,见下文:
uw
截断为零长度或创建用于写入的文本文件,默认权限ua
附加; 打开或创建用于在文件末尾写入的文本文件,默认权限uwb
截断为零长度或创建用于写入的二进制文件,默认权限uab
附加; 打开或创建二进制文件以在文件末尾写入,默认权限uw+
截断为零长度或创建文本文件进行更新,默认权限ua+
附加; 打开或创建用于更新的文本文件,在文件末尾写入,默认权限uw+b
或uwb+
截断为零长度或创建二进制文件进行更新,默认权限ua+b
或uab+
附加;打开或创建用于更新的二进制文件,在文件末尾写入,默认权限在底层系统支持这些概念的范围内,为写入而打开的文件应以独占(也称为非共享)访问打开。如果正在创建文件,并且模式字符串的第一个字符不是“u”,则在底层系统支持的范围内,该文件应具有文件权限,以防止系统上的其他用户访问该文件。如果正在创建文件并且模式字符串的第一个字符是'u',那么在文件关闭时,它应该具有系统默认的文件访问权限10)。
如果文件被成功打开,然后将指针
FILE
指向的由streamptr
将被设置为指向对象控制打开的文件。否则,指针FILE
指向的由streamptr
将被设置为一个空指针。退货
fopen_s
如果打开文件,该函数返回零。如果它没有打开文件或者存在运行时约束冲突,则fopen_s
返回一个非零值。10)这些权限与 fopen 创建文件的权限相同。
回答by paxdiablo
You canuse 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 以获取完整详细信息。
回答by Michael Burr
The fopen_s()
function has been added by Microsoft to the C runtime with the following fundamental differences from fopen()
:
该fopen_s()
函数已由 Microsoft 添加到 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).
- 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).
- if the "u" specified is notused 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.
- 如果文件被打开用于写入(模式中指定的“w”或“a”),则文件被打开用于独占(非共享)访问(如果平台支持)。
- 如果在带有“w”或“a”说明符的 mode 参数中使用了“u”说明符,那么在文件关闭时,它将具有系统默认权限,其他用户可以访问该文件(可能没有如果这是系统默认值,则访问)。
- 如果在这些情况下未使用指定的“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.
Microsoft 选择弃用是fopen()
为了鼓励 Windows 开发人员有意识地决定他们的应用程序使用的文件是否具有松散的权限。
Jonathan Leffler's answerprovides the proposed standardization language for fopen_s()
. I added this answer hoping to make clear the rationale.
Jonathan Leffler 的回答为fopen_s()
. 我添加了这个答案,希望能阐明理由。
回答by veefu
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' 使用的 FILE 结构的一些实现将文件描述符定义为 '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”的错,但人们可以看到摆脱旧接口束缚的优点;弃用的选择可能是基于与过时的实现保持二进制兼容性的痛苦。
回答by rein
The new versions do parameter validationwhereas the old ones didn't.
新版本进行参数验证,而旧版本则没有。
See this SO threadfor more information.
有关更多信息,请参阅此 SO 线程。
回答by laalto
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
并接受一个FILE**
参数来存储文件指针。