读取文件和未定义的行为

时间:2016-12-19 00:11:20

标签: c++ c++11 io ifstream

最近我偶然发现了一篇帖子:How to read an entire file into memory in C++,其中描述了不同的阅读文件的技巧。每种方法都会对其与未定义行为相关的效率或风险进行评论。 在列表中,提供了以下示例:

// Bad code; undefined behaviour
in.seekg(0, std::ios_base::end);

基本上以这种或类似的形式通常用于实际读取文件大小。 简而言之,该帖子中提出的推理是C standard (N1570) §7.21.3表明:

  

将文件位置指示器设置为文件结尾,如同   fseek(file,0,SEEK_END)具有二进制流的未定义行为   (因为可能是尾随空字符)或任何流有   状态相关的编码,不能确定地在初始结束   转变状态。

footnote 268为:

  

文件无需在初始移位状态下开始或结束

为了确认C ++ 11的上述内容,还有一个对C++ standard draft (N3242) 27.9.1.1的附加引用,其中指出:

  

读取和写入由...控制的序列的限制   类basic_filebuf的对象与读写相同   使用标准C库文件。

根据cppreferencebasic_filebufbasic_ifstream(内部缓冲区)的实现的一部分。 ifstream实施的哪些要点也应该用表示的行为来承担。

根据我从描述和我设法挖掘的内容中所理解的,此问题主要与面向广播的流有关,这些流可能不会在initial shift state中结束。

在我看来,由于文件大小计算的流行用法,这不是典型的情况。对我来说,这个话题还不是很清楚。因此,以下问题

  • 实际上initial state shift是什么?我认为它与数据集群无关。更多的是多字节字符编码,但这种方式不会仅限于非二进制流吗?
  • 我们实际上是在处理wide-narrow-oriented个流吗?我知道:"A newly opened stream has no orientation."并且方向是在对流的第一次I / O调用时决定的。但在实践中,让我们说,任何默认值依赖于流类型,系统,区域设置或其他东西?
  • 如果还没有回答或表示,那么何时会出现这种未定义的行为的实际例子是什么?从某种意义上说,人们可以重现它。

1 个答案:

答案 0 :(得分:3)

"shift state" - 实际上限于多字节文本流(以及EOL处理\r\n vs \n)和问题将仅限于文本流。< / p>

但这不是唯一的问题。从你引用的文章中我强调:

  

某些平台将文件存储为固定大小的记录。如果文件短于记录大小,则填充块的其余部分。当你寻求“结束”时,为了效率而它只是跳到你最后一个块的末尾...在数据的实际结束后可能长 ,在一堆填充之后

fseek(p_file, 0, SEEK_END)后跟ftell(...)只有EOF标志未提出才能提供有效答案。
阅读引用的“解决方案(真正的大文件)”部分,因为它提供了详细信息,特别是:
步骤4.“使用seekg()将流恢复到起始位置。这也将清除EOF标志。

评论中的问题:

  

您是否了解哪些平台特别?

谷歌让我进入this list面向记录的文件系统 - 主要是大型机,其中一些仍在使用。

另一个可能是“记录文件”区域的区域:“云”。你永远不知道什么时候有人会(重新)化身Distributed Data Management Architecture并且遇到record-oriented files可以解决的问题。 对于我所知道的(几乎没有),NFS 可能已经在做了:RFC谈到“记录锁定”。

在C / C ++中编写“真正标准的,跨平台兼容的软件”时,我会注意标准并尊重这个问题。