为什么没有std :: ios_base :: trunc的std :: ofstream截断?

Ben*_*ler 8 c++ ofstream

根据此C ++参考:http : //www.cplusplus.com/reference/fstream/ofstream/ofstream/ ,的默认打开模式std::ofstreamios_base::out,并且没有提及其他隐式模式。因此,我希望如果用小文件覆盖大文件,则大文件的“超出”部分应保持不变,并且仅文件的第一部分应由较短的新数据代替。

另一方面,《 Apache C ++标准库用户指南》(http://stdcxx.apache.org/doc/stdlibug/30-3.html)在第30.3.1.2段的注释中指出:“对于输出文件流,打开模式输出等效于out | trunc,也就是说,您可以省略trunc标志。但是,对于双向文件流,必须始终明确指定trunc。

我已经试过这段代码:

#include <fstream>

int main()
{
    std::ofstream aFileStream("a.out", std::ios_base::out);
    aFileStream << "Hello world!";
    aFileStream.close();

    std::ofstream aFileStream2("a.out", std::ios::out);
    aFileStream2 << "Bye!";
    aFileStream2.close();
}
Run Code Online (Sandbox Code Playgroud)

无论是Windows上的g ++ 8.1和Linux上的g ++ 6.3,Apache文档似乎都是正确的。大文件被截断,在第二个文件流中写入较短的字符串后,没有任何内容。

为什么会这样呢?cplusplus.com错误吗?抑或行为令人沮丧?

L. *_* F. 8

每个[ofstream.cons] / itemdecl:2

explicit basic_ofstream(const char* s,
                        ios_base::openmode mode = ios_base::out);
Run Code Online (Sandbox Code Playgroud)

因此,的默认模式ofstreamout。然而,每[标签:filebuf.open.modes] out并且out | trunc都对应于标准输入输出等效"w",所以它们是等价的。根据C11 7.21.5.3

w:截短为零长度或创建要写入的文本文件

因此,正确的说默认模式是out,正确的说默认模式等于out | trunc。这是有保证的行为。

另一方面,根据[fstream.cons] / itemdecl:2

explicit basic_fstream(
  const char* s,
  ios_base::openmode mode = ios_base::in | ios_base::out);
Run Code Online (Sandbox Code Playgroud)

因此,的默认模式fstreamin | out。每[标签:filebuf.open.modes] in | out对应于"r+",而in | out | trunc对应于"w+",所以它们是不等效的。根据C11 7.21.5.3

r+:打开文本文件进行更新(读取和写入)
w+:截断长度为零或创建文本文件进行更新

因此,fstream除非您指定,否则不要截断trunc。请注意,如果所需文件不存在,r+将失败,而不是创建文件。相反,在这种情况下ww+两者都创建一个新文件。

(另请参见:fopen关于cppreference)