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

时间:2013-05-22 07:17:22

标签: c stream buffer fseek ungetc

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

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

fseek()fsetpos()rewind() 放弃前一次调用对ungetc()的影响是什么?你能告诉我如何它完成了吗?我的意思是,鉴于我们已经打开了一个文件进行读取并将其复制到缓冲区中。现在使用ungetc()我们已经更改了一些字符缓冲。即使经过多方努力,我仍然无法理解:

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

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

  • 的此链接中约ungetc()ftell

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

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

2 个答案:

答案 0 :(得分:1)

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

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

想象一下putback_char被初始化为值EOF,表示“没有回放字符”,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 */
}

清除回传的功能只需将EOF分配给putback_char

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

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

  

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

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

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

答案 1 :(得分:0)

让我们从头开始,

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

回滚功能将与流关联的文件指针重新定位到文件的开头。回调调用类似于

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

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

现在回答您的第二个问题 - 成功的干预呼叫(使用流指向的流)到文件定位功能会丢弃该流的任何推回字符。与流对应的外部存储器未更改