撤消ungetc()的效果:“如何”fseek(),rewind()和fsetpos()这样做?每次都重新填充缓冲区吗?

嗯!!我怎么能把整件事放在一个明确的问题上!!让我试试:

我知道使用fopen()打开的文件被缓冲到内存中。我们使用缓冲区来提高效率。在从文件中读取文件时,首先将文件内容读入缓冲区,然后从该缓冲区中读取。类似地,在对文件的写入中,首先将内容写入缓冲区,然后写入文件。

但是fseek()fsetpos()rewind() 丢弃之前调用ungetc()呢? 你能告诉我它是如何完成的吗?我的意思是,鉴于我们已经打开了一个文件进行读取并将其复制到缓冲区中。现在使用ungetc()我们已经更改了缓冲区中的一些字符。这就是我刚才失败的地方即使经过多方努力也能理解

  • 以下是关于ungetc()说法 – “对fseek,fsetpos或fwindpos的调用会丢弃之前使用此函数重新放入其中的任何字符。” – 如何放弃已放入缓冲区的字符?一种方法是删除被删除的原始字符,并将每个放入的新字符识别并替换为原始字符。但这似乎效率很低。另一种选择是将原始文件的副本加载到缓冲区中,并将文件指针放在预期的位置。这两个方法的fseek,fsetpos或rewind采取放弃使用ungetc()放置的字符?

  • 对于文本流,流中未读字符的存在,使用ungetc()放入的字符如何影响ftell()的返回值?我的混淆来自关于ftell()ungetc()的以下行关于ftell这个链接( SOURCE )

“对于文本流,数值可能没有意义但仍然可以用于稍后使用fseek将位置恢复到相同位置( 如果使用ungetc放回的字符仍然等待被读取,则行为未定义 )。”

  • 关注上段的最后一行, pending of being read与“ungetc() – 获得的”字符被丢弃有关吗? 每次我们读取使用ungetc()放入流中的ungetc() ,它是否在读取后被丢弃

回放角色的一个好的心智模型就是它是一些额外的小属性,它悬挂在FILE *对象上。 想象一下你有:

 typedef struct { /* ... */ int putback_char; /* ... */ } FILE; 

想象一下, putback_char初始化为值EOF ,表示“没有putback char”, ungetc只是将字符存储到该成员。

想象一下,每次读取操作都通过getc ,而getc执行如下操作:

 int getc(FILE *stream) { int ret = stream->putback_char; if (ret != EOF) { stream->putback_char = EOF; if (__is_binary(stream)) stream->current_position--; return ret; } return __internal_getc(stream); /* __internal_getc doesn't know about putback_char */ } 

清除回putback_char的function只是将EOF分配给putback_char

换句话说,放回字符(并且只需要支持一个)实际上可以是与常规缓冲分开的微型缓冲区。 (考虑到即使是无缓冲的流也支持ungetc :这样的流必须将字节或字符放在某处。)

关于位置指示器,C99标准说:

对于文本流,在成功调用ungetc函数之后,其文件位置指示符的值未指定,直到读取或丢弃所有推回的字符。 对于二进制流,每次成功调用ungetc函数都会减少其文件位置指示符; 如果在呼叫之前它的值为零,则在呼叫之后它是不确定的。 [7.19.7.11 ungetc函数]

因此,您使用的www.cplusplus.com参考文献不正确; 当使用ungetc推回待处理字符时,未定义ftell的行为。 对于文本流,该值未指定。 访问未指定的值不是未定义的行为,因为未指定的值不能是陷阱表示。 如果在位置零处发生回退,则二进制流存在未定义的行为,因为该位置变为不确定。 Indeterminate意味着它是一个未指定的值,可能是陷阱表示。 访问它可能会使用错误消息暂停程序,或触发其他行为。

最好从马的口中获取编程语言和库规范,而不是从随机网站获取。

让我们从头开始,

 int ungetc(int c, FILE *stream); 

ungetc()函数应将c指定的字节(转换为unsigned char)推回到stream指向的输入流上。字符实际上被放回到输入流中,减少其内部文件位置,就像之前的getc一样操作被撤消。这只影响该流上的进一步输入操作,而不影响与其关联的物理文件的内容,这些内容不会被对此函数的任何调用修改。

 int fseek(FILE *stream, long offset, int whence); 

从文件开头以字节为单位测量的新位置应通过将偏移量添加到由whence指定的位置来获得。 指定的点是SEEK_SET文件的开头,SEEK_CUR的文件位置指示器的当前值,或者SEEK_END.fseek的文件结尾要么在设置文件位置之前刷新任何缓冲的输出,要么记住它以便它稍后将在文件中的适当位置写入

 int fsetpos(FILE *stream, const fpos_t *pos); 

fsetpos()函数根据pos指向的对象的值设置stream指向的流的文件位置和状态指示符,该值必须是从先前对同一流上的fgetpos()调用获得的值。

 void rewind(FILE *stream); 

倒带function将与流关联的文件指针重新定位到文件的开头。 呼叫倒带类似于

(void)fseek(stream,0L,SEEK_SET);

因此,当你看到ungetc()时,推回字符不会改变文件; 只有流的内部缓冲受到影响。所以你的第二个注释“另一个选项是将原始文件的副本加载到缓冲区并将文件指针放在预期的位置”是正确的。

现在回答你的第二个问题 – 一个成功的干预呼叫(用流指向的流)到文件定位function会丢弃该流的任何推回字符。 对应于流的外部存储器不变