freopen()关于缓冲(setvbuf())的预期行为?

问题描述 投票:5回答:1

为了implement freopen(),我提出了标准中的一项规范,据我所知,它实际上并未指定任何内容。

So ... freopen()将关闭流(忽略错误),清除其错误和EOF标志,重置宽方向,然后以给定模式重新打开流。这很清楚;这基本上是一个fclose()/ fopen()。即使未采用这种方式定义,也很清楚这是预期的。

但是,关于setvbuf()可能对流所做的事情,我有两个问题-设置用户分配的缓冲区和/或更改缓冲区策略。


问题1。

1]是否期望freopen()将其恢复为默认状态,就像它实际上已调用了fopen()一样?还是无论用户通过旧setvbuf()设置的内容,它都有望延续到新的流中?这涉及缓冲存储器和缓冲策略,但是这里的主要问题是缓冲存储器。

fclose()的规范指定用户通过setvbuf()与流相关联的任何缓冲区都已取消关联,即,用户现在可以将其free()设置为对象。

但是freopen()仅指定它关闭与流相关联的文件,而不是fclose()使用它。

因此,在freopen()之后,用户关联的缓冲存储器是否仍与该流关联?


问题2。

freopen()可以想象用于在调用时实际上未与打开的文件关联的FILE结构上(因为尝试关闭文件的错误将被忽略)。

该文件结构可能是以前打开的流,带有用户分配的缓冲存储器和缓冲策略。是freopen()遵循这些设置,即重新将缓冲存储器/策略与“重新”打开的文件相关联,还是将结构重新初始化为默认值,假设用户free()在[C0之后] d了缓冲存储器]之前是否已在文件中?


我接受。

[看第二季度,我没有看到标准库可靠地确定带有用户分配的缓冲存储器的当前未打开的fclose()结构是否仍“拥有”该缓冲存储器,或者用户是否拥有该缓冲存储器的方法。已经回收了该内存。 (可以想象,该内存可能是本地的,即即使我愿意去那里也不是由FILE / malloc()处理的内存列表的一部分,而且这是标准库函数所期望的非常不复杂的工作。)

缓冲策略的类似考虑。

因此,据我所知,唯一处理方式[free()将“与指定流关联的任何文件”的关闭视为“真实” [C0 ],然后将缓冲存储器/策略重新设置为默认值。

我对这种理解是正确的,还是对Q1 / Q2有替代答案?
c language-lawyer standards standard-library c-standard-library
1个回答
2
投票
C标准未声明以任何方式修改了缓冲状态。

整个freopen()是(包括fclose()):

7.21.5.4 C11 freopen() specification功能

简介

[[1

freopen()

说明

[2 footnote 272函数打开名称为指向的字符串的文件freopen的值,并将stream指向的流与其关联。 #include <stdio.h> FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream); 参数的用法与freopen函数中的用法相同。272)

3

如果filename是空指针,则mode函数将尝试执行以下操作:将流的模式更改为fopen指定的模式,就像当前使用了与该流关联的文件的名称。由实现定义,允许哪些模式更改(如果任何),以及在什么情况下。

[4

filename函数首先尝试关闭任何与指定的流关联。无法关闭文件是忽略了。流的错误和文件结束指示符是已清除。

返回

5如果打开操作,freopen函数将返回空指针失败。否则,mode返回freopen的值。


272)

freopen功能的主要用途是更改文件与标准文本流(freopenstreamfreopen)相关联,例如这些标识符不必是该值可修改的左值可以分配stderr功能返回的值。
对我来说,关键词是

将流指向的流与其关联。先前存在的[[stdin指向的流]具有一个新文件关联-这就是所有。通过不对缓冲进行任何更改,在我看来这意味着保留了当前的缓冲状态,因为stdout只是associating一个新的文件,并具有preexisting流模式。根据我的阅读,仅应对标准中明确指出的fopen流进行更改。也请注意第4段:stream函数首先尝试关闭与指定流关联的任何文件。

同样,标准引用了

指定流。对我来说,结论似乎不可避免:freopen()不会创建新的流。它只是将先前存在的流指向一个新文件-这就是全部。]此读数-当前流的缓冲区状态未修改-当前实现支持。它们不会修改现有流的缓冲状态。

FILE *freopen(很可能是当前的Solaris实现)似乎都没有改变原始缓冲区的状态,除了在关闭文件之前刷新任何缓冲区之外。

freopen()功能确实没有正确指定。 GLIBC freopen() implementation

应用用途

freopen()函数通常用于将与the OpenSolaris/Illumos implementationfreopen()POSIX has this to say关联的预打开的流附加到其他文件。由于当freopen()参数为stdin时不需要实现支持任何流模式更改,因此可移植应用程序不能依赖于使用stdout来更改流模式,因此不鼓励使用此功能。该功能最初是添加到ISO C标准中的,以便于将stderrpathname更改为二进制模式。由于此模式下的NULL字符对POSIX系统无效,因此在POSIX应用程序中不需要使用此功能。但是,即使忽略freopen(),成功调用stdin也会起作用。特别是对于常规文件,它会截断文件并将流的文件位置指示符设置为文件的开头。这些副作用可能是ISO / IEC 9899:1999标准中指定功能的方式的意外结果,但除非或直到ISO C标准被更改,否则成功调用stdout的应用程序将在在诸如以下情况下符合系统要求的意外方式:

'b'

这将导致

file3仅包含第二次调用

appl

的输出。
© www.soinside.com 2019 - 2024. All rights reserved.