流::seekoff 是否更新了输入序列

Does stream::seekoff update the input sequence?

本文关键字:输入 更新 seekoff 是否      更新时间:2023-10-16

In [filebuf.virtuals]:

pos_type seekoff(off_type off, ios_base::seekdir way,
ios_base::openmode which
= ios_base::in | ios_base::out) override;

效果:width表示a_­codecvt.encoding()。如果is_­open() == falseoff != 0 && width <= 0,则定位操作失败。否则,如果way != basic_­ios​::​curoff != 0,并且如果输出了最后一个操作,则更新输出序列并写入任何取消移位序列。接下来,寻找新的位置:如果width > 0,则呼叫fseek(file, width * off, whence),否则呼叫fseek(file, 0, whence)

它没有提到此函数更新输入序列。相比之下,seekpos确实更新了输入序列:

pos_type seekpos(pos_type sp,
ios_base::openmode which
= ios_base::in | ios_base::out) override;

如果可能,更改文件位置以对应于存储在sp中的位置(如下所述)。更改文件位置执行如下:

  1. 如果(om & ios_­base​::​out) != 0,则更新输出序列并写入任何未移位序列;

  2. 将文件位置设置为sp,就像通过调用fsetpos一样;

  3. 如果(om & ios_­base​::​in) != 0,则更新输入序列;

那么seekoff能保证更新输入序列吗?

对于一个具体示例,请考虑:

#include <fstream>
#include <iostream>
int main()
{
std::fstream f("test.txt"); // test.txt contains "test"
char ch;
f >> ch;
f.rdbuf()->pubseekoff(0, std::ios_base::beg);
f >> ch;
std::cout << ch;
}

程序是否保证输出t

我可以看到你的观点朋友,事实上,这可能不仅仅是你自己一些困惑的根源。

简短的回答:

是的,seekoff会像seekpos一样更新输入序列。seekoffseekpos在调用、输入或输出(或两者)更新哪个序列方面行为相同。

详细解释

不是仅仅通过惯例,而是根据标准本身,seekoffseekpos的行为都被定义为依赖于ios_base::openmode which论点。在另一个类模板中可以看出,stringbuf,派生自与filebuf相同的父级,seekoff的覆盖明确声明,对于(which & ios_­base​::​in) == ios_­base​::​in调用将定位输入序列;对于(which & ios_­base​::​out) == ios_­base​::​out调用将定位输出序列;对于(which & (ios_­base​::​in | ios_­base​::​out)) == (ios_­base​::​in | ios_­base​::​out)way ==ios_­base​::​begios_­base​::​end调用将同时定位输入和输出序列。

但是,当直接在标准面前工作时,人们不必期望事物只是呈现自己。请参阅父类streambuf下的此处:

pos_type seekoff(off_type off, ios_base::seekdir way,
ios_base::openmode which
= ios_base::in | ios_base::out) override;

效果:以为派生自basic_­streambuf的每个类单独定义的方式更改一个或多个受控序列中的流位置...

因此,通过更仔细地查看您自己提供的有关filebufseekpos报价的标准:

pos_type seekpos(pos_type sp,
ios_base::openmode which
= ios_base::in | ios_base::out) override;

如果可能,更改文件位置以对应于存储在sp中的位置(如下所述)。更改文件位置执行如下:

  1. 如果(om & ios_­base​::​out) != 0,则更新输出序列并写入任何未移位序列;

  2. 将文件位置设置为sp,就像调用fsetpos一样;

  3. 如果(om & ios_­base​::​in) != 0,则更新输入序列;

以下行说:

其中om是传递给最后一次调用 open() 的开放模式。

因此,这意味着您无法在调用本身中指定要更新的序列。例如,这里的标准说实现应该明显忽略(!)om参数。

我们不必错过的另一点是您提供的关于seekoff的报价中,其中说:

接下来,寻找新的位置:如果width > 0,则呼叫fseek(file, width * off, whence),否则呼叫fseek(file, 0, whence)

所以在背后,它只是一个对fseek的呼吁。但是在哪个特定的文件对象上?输入和输出是否有单独的?我相信我们正在寻找的答案出现在 filebif 下的规范中:

§ 27.9.1.1

  1. 类basic_filebuf将输入序列和 带有文件的输出序列。
  2. 读取和写入由类对象控制的序列的限制 basic_filebuf与使用标准 C 库进行读写相同 文件。
  3. 特别:
    • 如果文件未打开以供读取,则无法读取输入序列。
    • 如果文件未打开以进行写入,则无法写入输出序列。
    • 输入序列和输出序列都保持联合文件位置。

例如,seekoffseekpos的行为对于调用、输入或输出(或两者)正在更新的序列相同,并且仅由传递给open()的内容确定。

另外,大约 5 年前刚刚遇到这个问题,我看到:fstream seekg()、seekp() 和 write()

编辑,以进一步澄清:

请注意seekoff的规范说:

如果输出了最后一个操作,则更新输出序列和写入任何未移位序列。

seekpos还说:

更新输出序列并写入任何未移位序列;

seekoff的备注部分定义了"编写任何未移位序列"的含义。因此,对于这两种方法,它应该是等效的。但随后两者都进一步说明:seekoff说它叫fseekseekpos说它叫fsetpos(在这方面与fseek相同)。

当考虑到上述§ 27.9.1.1节中的第2点在C11标准ISO/IEC 9899:2011中进行了解释时,可以找到其原因,甚至提到最后一个操作是输出位:

§7.21.5.3fopen函数

¶7 当文件以更新模式打开时("+"作为 上面的模式参数值列表),输入和输出都可以在 关联的流。但是,输出后不应直接跟着没有 对fflush函数或文件定位函数(fseek的干预调用,fsetposrewind),并且输入后不应直接跟着输出,而没有 对文件定位函数的干预调用,除非输入操作遇到文件末尾。

因此,要回答您在下面的评论,seekoff是否会更新输入序列与是否输入最后一个操作无关。如果最后一个操作不是输入的,那么上面讨论的取消移位序列存在技术性。但是整个stream类的部分想法是以一种不会打扰您进行此类维护工作的方式封装 i/o。