stream :: seekoff会更新输入序列吗?

xsk*_*xzr 10 c++ buffer stream language-lawyer

[filebuf.virtuals]中:

pos_type seekoff(off_type off, ios_base::seekdir way,
                 ios_base::openmode which
                   = ios_base::in | ios_base::out) override;
Run Code Online (Sandbox Code Playgroud)

效果:让我们来width表示a_­codecvt.encoding().如果is_­open() == false,或者off != 0 && width <= 0,则定位操作失败.否则,如果way != basic_­ios?::?cur还是off != 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;
Run Code Online (Sandbox Code Playgroud)

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

  1. if (om & ios_­base?::?out) != 0,然后更新输出序列并写入任何非移位序列;

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

  3. if (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;
}
Run Code Online (Sandbox Code Playgroud)

程序是否保证输出t

Rei*_*ica 2

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

\n\n

简短回答:

\n\n

是的,seekoff将按照意愿更新输入序列seekpos。对于调用、输入或输出(或两者)更新哪个序列,两者的seekoff行为相同。seekpos

\n\n

长解释

\n\n

不仅仅是按照惯例,而是根据标准本身,两者的行为seekoffseekpos被定义为依赖于ios_base::openmode which参数。正如在另一个类模板 中所看到的,stringbuf派生自与 相同的父级filebuf的覆盖seekoff显式声明该(which & ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bin) == ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bin 调用将定位输入序列;对于(which & ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bout) == ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bout 调用将定位输出序列;对于(which & (ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bin | ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bout)) == (ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bin | ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bout)way ==ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bbegios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bend 调用将定位输入和输出序列

\n\n

但是,当直接在标准面前工作时,人们不必期望事情会自然而然地呈现出来。请参阅父类下的此处streambuf

\n\n
\n
pos_type seekoff(off_type off, ios_base::seekdir way,\n                 ios_base::openmode which\n                   = ios_base::in | ios_base::out) override;\n
Run Code Online (Sandbox Code Playgroud)\n\n

效果:以一种为派生自...的每个类单独定义的方式改变一个或多个受控序列中的流位置。basic_\xc2\xadstreambuf

\n
\n\n

因此,通过更仔细地查看您自己提供的报价seekpos标准filebuf

\n\n
\n
pos_type seekpos(pos_type sp,\n                 ios_base::openmode which\n                   = ios_base::in | ios_base::out) override;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
    \n
  1. 如果(om & ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bout) != 0,则更新输出序列并写入任何未移位序列;

  2. \n
  3. 将文件位置设置为sp好像通过调用fsetpos;

  4. \n
  5. 如果(om & ios_\xc2\xadbase\xe2\x80\x8b::\xe2\x80\x8bin) != 0,则更新输入序列;

  6. \n
\n
\n\n

下面一行说:

\n\n
\n

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

\n
\n\n

因此,这意味着您无法在调用本身中指定要更新哪个序列。正如这里的标准所说,实现应该简单地忽略(!)om

\n\n

我们不能错过的另一点是您提供的有关seekoff,其中写道:

\n\n
\n

接下来,寻找新位置: if width > 0callfseek(file, width * off, whence),否则 callfseek(file, 0, whence)

\n
\n\n

所以底层只是对fseek. 但是在哪个特定的 FILE 对象上呢?输入和输出有单独的吗?我相信我们正在寻找的答案出现在filebuf下的规范中下的规范中:

\n\n
\n

\xc2\xa7 27.9.1.1

\n\n
    \n
  1. basic_filebuf 类将输入序列和输出序列与文件相关联。
  2. \n
  3. 读取和写入由类 basic_filebuf 的对象控制的序列的限制与使用标准 C 库文件读取和写入的限制相同。
  4. \n
  5. 特别是:\n\n
      \n
    • 如果文件未打开以进行读取,则无法读取输入序列。
    • \n
    • 如果文件未打开用于写入,则无法写入输出序列。
    • \n
    • 为输入序列和输出序列维护联合文件位置。
    • \n
  6. \n
\n
\n\n

如图所示,对于调用、输入或输出(或两者)更新哪个序列, 和 的行为是相同的,并且它仅由传递给 的内容seekoff决定。seekposopen()

\n\n

另外,大约 5 年前就遇到过这个问题,我看到:fstreameekg()、seekp() 和 write()

\n\n

编辑,以进一步澄清:

\n\n

请注意规范seekoff说:

\n\n
\n

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

\n
\n\n

seekpos还说:

\n\n
\n

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

\n
\n\n

注释部分seekoff定义了 \xe2\x80\x9cWrite any unshift sequence\xe2\x80\x9d 的含义。因此,这两种方法应该是等效的。但随后两者都进一步指定:seekoff说它调用fseekseekpos说它调用(在这方面fsetpos相同)。fseek

\n\n

这样做的原因,甚至提到最后一个操作是输出位,是在考虑上面提到的 \xc2\xa7 27.9.1.1 节中的第 2 点时发现的,在 C11 标准 ISO/IEC 9899:2011 中对此进行了解释:

\n\n
\n

\xc2\xa77.21.5.3fopen函数

\n\n

\xc2\xb67 当使用更新模式打开文件时(\'+\' 作为上面模式参数值列表中的第二个或第三个字符),输入和输出都可以在关联的流上执行。但是,如果没有对函数fflush或文件定位函数(fseek、\n fsetposrewind)的中间调用,输出后面不得直接跟有输入,并且在没有对函数或文件定位函数( 、\n 或 )进行中间调用的情况下,输入后面不得直接跟有输出。文件定位功能,除非输入操作遇到文件结尾。

\n
\n\n

所以回答你下面的评论,是否seekoff会更新输入序列是不管最后一个操作是否输入的。如果没有输入最后一个操作,则存在上面讨论的未移位序列的技术细节。但整个类的部分想法stream是以一种不会让您因此类维护工作而困扰的方式封装 I/O。

\n