【问题标题】:Why does the C++ standard handle file seeking the way it does?为什么 C++ 标准会以这种方式处理文件?
【发布时间】:2020-04-07 06:45:15
【问题描述】:

C++ 使用streamoff 类型来表示(文件)流中的偏移量,并在 [stream.types] 中定义如下:

using streamoff = implementation-defined ;

streamoff 类型是有符号基本整数类型之一的同义词,其大小足以表示操作系统的最大可能文件大小。第287章)

287) 通常很长很长。

这是有道理的,因为它允许在大文件中进行查找(而不是使用可能只有 32 位宽的 long)。

[filebuf.virtuals] 定义basic_filebuf 在文件中查找的函数如下:

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

off_type 等价于streamoff,参见 [iostreams.limits.pos]。但是,该标准随后继续解释该功能的效果。我被最后一句话激怒了,这需要致电fseek

效果:让width 表示a_codecvt.encoding()。如果is_open() == false,或off != 0 && width <= 0,则定位操作失败。否则,如果 way != basic_ios::curoff != 0,并且 如果输出了最后一个操作,则更新输出序列并写入任何 unshift 序列。 接下来,寻找新的位置:如果width &gt; 0,调用fseek(file, width * off, whence),否则 拨打fseek(file, 0, whence)

fseek 接受 long 参数。如果off_typestreamoff 被定义为long long(按照标准的建议),这可能会导致在调用fseek(file, width * off, whence) 时向下转换为long(导致潜在的难以诊断的错误)。这对首先引入 streamoff 类型的整个理由提出了质疑。

这是故意的还是标准中的缺陷?

【问题讨论】:

  • 缺陷看起来像。
  • 我想我看到 gcc libstdc++ 使用了fseeko64
  • 副手,它看起来不像seekoff 一定使用 fseek 在引擎盖下。相反,fseek 的(可能是熟悉的?)行为用于解释 seekoff 正在做什么。
  • @jjramsey 这也是我的印象。但是,它的措辞方式似乎暗示了一种要求而不是一种解释。
  • @jjramsey 我同意“效果”部分可以合理地解释为它实际上不必调用fseek,只要它具有相同的效果。但是偏移量小于LONG_MIN 或大于LONG_MAXfseek 没有效果,因此解释充其量是不完整的,至少对于streamofflong 更宽的实现而言。

标签: c++ file language-lawyer seek c++20


【解决方案1】:

我认为您从中得出的结论是,C++ 流和fseek 之间存在不匹配会导致运行时错误,这是不正确的。情况似乎是:

  1. long 为64 位的系统上,streamoff 定义为longseekoff 函数调用fseek

  2. long 为 32 位但操作系统支持 64 位文件偏移的系统上,streamoff 定义为 long longseekoff 调用名为 fseekofseeko64 的函数接受 64 位偏移量。

这是我的Linux系统上seekoff定义的sn-p:

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFS 代表Large File Support

结论:虽然标准建议的 streamoff 定义表面上与 seekoff 调用 fseek 的要求相冲突,但库设计人员明白他们必须调用接受全部偏移范围的 fseek 的变体操作系统支持。

【讨论】:

  • @ypnos 我没有投反对票,我觉得这个答案很有用。我猜有人投了反对票,因为它没有抓住重点。问题不在于在这方面存在忽略标准的健全实现,问题在于需要忽略标准才能使实现健全。
  • The situation seems to be: - 情况是不允许实现在seekoff中不调用fseek。它必须调用fseek,它没有,standard 说它必须调用。我可以争辩说这个实现是无效的。我相信它没有回答这个问题。哦,找到llvm,它调用fseeko
  • 仅供参考,VC++ 为这个函数调用_fseeki64;这似乎也违反了标准的规定。
  • 这是实施者意识到问题而忽略标准的情况。我很高兴他们做到了,但标准确实需要修正。
  • 有些人对标准的理解过于严格。并不要求实现从字面上调用一个名为fseek 的函数。在其他地方,该标准将某事描述为“好像通过调用fseek(...)”。如果它非常关心直接调用fseek,那么该声明将有所不同。说真的,如果你正在实现一个 C++ 库,你会怎么做?您是否会坚持使用 64 位文件偏移量的低 32 位调用 fseek,因为文档告诉您这样做?您的客户会为此感谢您吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-28
  • 1970-01-01
  • 2012-05-11
  • 2014-03-21
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多