为什么 C++ 标准会按照它的方式处理文件?

jce*_*ed2 17 c++ file seek language-lawyer c++20

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

using streamoff = implementation-defined ;

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

287) 通常很长很长。

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

[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,并且如果最后一个操作是输出,则更新输出序列并写入任何非移位序列。接下来,寻找新的位置:如果width > 0,调用fseek(file, width * off, whence),否则调用fseek(file, 0, whence)

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

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

Wil*_*urn 6

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

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

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

这是seekoff我的 Linux 系统上定义的片段:

#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
Run Code Online (Sandbox Code Playgroud)

LFS 代表大文件支持

结论:虽然标准提出了一个streamoff表面上与seekoffinvoke要求冲突的定义fseek,但库设计者明白他们必须调用fseek接受操作系统支持的全部偏移量的变体。

  • `情况似乎是:` - 情况是不允许实现在`seekoff`中不调用`fseek`。它必须调用 `fseek`,但它没有,[standard](http://eel.is/c++draft/filebuf#virtuals-13) 说它必须调用。我可以说这个实现是无效的。我相信这并不能回答问题。哦,找到了[llvm](https://github.com/llvm-mirror/libcxx/blob/master/include/fstream#L950),它调用`fseeko`。 (6认同)