说双向文件声明不隐式设置标志是否正确

Is it correct to say that bidirectional file declarations do not set flags implicitly?

本文关键字:标志 设置 是否 文件 声明      更新时间:2023-10-16

这里的这种说法似乎不正确:

另一方面,双向文件流没有标志 隐式设置。这是因为双向流 不必在所有情况下都处于输入和输出模式。你 可能想要打开双向流以进行只读或写入 只。因此,双向文件流没有隐式输入或 输出模式。您必须始终设置双向文件流的打开 模式显式。

否则,此代码将无法编译。

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    fstream file("novo.txt", ios::out);
    char i;
    file >> i;
} 

语句适用于 gcc

这里的这种说法似乎不正确:[...]

我不知道标准或Visual Studio,但我知道我正在使用的C++,这是来自GCC的那个。在那里,您可以查看相关的标题。

oistream::open看起来像这样:

inline void
istream::open(const char* __s, ios_base::openmode __mode = ios_base::in) {
  if (!_M_filebuf.open(__s, __mode | ios_base::in))

所以你这里有两件事:一个默认的函数参数,以防你在调用方法时没有指定一个,以及一个强制标志它总是被或进入提供的模式。因此,无论您指定哪种模式,输入模式都将始终添加到您的规范中。其他代码,特别是构造函数,将委托给此代码。类似的情况也发生在ofstream::open .另一方面,fstream::open默认参数,但没有强制参数:

inline void
fstream::open(const char* __s,
              ios_base::openmode __mode = ios_base::in | ios_base::out) {
  if (!_M_filebuf.open(__s, __mode))

因此,不传递任何模式都是可以的(至少在这个实现中,但请阅读@kmote的答案以获取更多详细信息),但是如果您确实传递了任何模式,那么您必须传递inout或两者兼而有之,因为不会将强制模式添加到您指定的模式中(或未指定)。

这是我阅读 Apache 文档的方式,来源支持我的观点,至少对于我的实现而言。由于所有这些都在模板化代码中,因此您可以查看来自不同编译器的标头,以了解它如何处理这些情况。因此,请查看VS标头,查找basic_fstream并查看其方法是如何实现的。

缺少编译器错误

否则,此代码将无法编译。

代码打开一个双向流仅用于输出,然后尝试从中输入内容。没有理由无法编译。流的静态类型是fstream的,即双向的。只有在运行时,您才会将具有特定含义的某个标志传递给构造函数。编译器(通常)不会检查这一点,因此当代码无法实际从流中读取时,代码在运行时将行为异常。

请注意,我不确定 Windows 是否真的支持仅打开文件进行输出。操作系统支持的唯一文件模式很可能是只读和读写。(请注意,我只是在这里推测。在这种情况下,即使在运行时,打开文件仅用于输出并在之后读取也不会有问题,因为仅使用 out 打开文件或使用 in|out 打开文件没有区别。为了便于移植,应该选择正确的模式,因为那里有支持只写文件的内核。

虽然历史上对这个问题存在一些混淆,但我相信你引用的说法确实具有误导性,但不是因为你的例子中的原因。双向文件流确实隐式设置了标志,如文档中所述:

void open(
const char *_Filename,
ios_base::openmode _Mode = ios_base::in | ios_base::out,
int _Prot = (int)ios_base::_Openprot
);

基于 Apache 语句,我不希望您的代码示例失败,因为它明确将标志设置为 ::out。另一方面,我希望这段代码失败:

int main()
{
    fstream file("novo.txt");
    char i;
    file >> i;
} 

但是根据 MSDN 文档,这段代码也不会失败,文件将默认为 ios_base::in & out(因此,Apache 语句并不完全准确)。