【问题标题】:EOF vs basic_ios::eof() on GCC 5.2.1GCC 5.2.1 上的 EOF 与 basic_ios::eof()
【发布时间】:2017-06-27 08:25:59
【问题描述】:

在使用 GCC 5.2.1 编译的程序上,ifstream 的状态在到达文件末尾时不会切换到 basic_ios::eof(),即条件 if(eof()) 在已到达文件末尾 — 而在 Visual Studio 2015 上编译的相同代码的行为与预期相同:到达文件末尾时,basic_ios::eof()if 条件下计算为 true

我用if(bad()) 替换了if(eof()),然后用if(fail()) 替换了false,所有这些都被评估为false。但是,当我改为放置 EOF 宏时,if(EOF) 的计算结果为 true——就像 if(eof()) 在 VS 编译的程序上所做的那样。

std::basic_ios::eof() 不能处理使用 GCC 编译的程序的原因可能是什么?

PS:下面是程序的代码

#include <string>
#include <iostream>
#include <fstream>
#include <regex>

using namespace std;
using namespace std::chrono;

int ex10()
{
    ifstream in{ "school.txt" };
    if (!in) cout << "The 'school.txt' file was not opened.\n";

    string line;

    regex header{ R"(^([\w]+)(\t{2}\w+\s*\w*)(\t\w+\s*\w*)(\t\w+\s*\w*)$)" };
    regex row{ R"(^(\w+\s*\w*)(\t{1,2}\d+)(\t{2}\d+)(\t{2}\d+)$)" };

    if (getline(in, line)) {
        smatch matches;
        if (!regex_match(line, matches, header))
            cerr << "Wrong header format.\n";
    }
    int linenum = 0;
    int boys = 0;
    int girls = 0;

    ofstream out{ "schoolCompressed.txt" };
    if (!out) cout << "The output file was not created.\n";
    string prevLine;
    int accumBoys;
    int accumGirls;
    int accumTot;

    while (getline(in, line)) {
        ++linenum;
        smatch matches;
        if (!regex_match(line, matches, row))
            cerr << "Row #" << linenum << " doesn't match the format.\n";


        int curr_boy = stoi(matches[2]);
        int curr_girl = stoi(matches[3]);
        int curr_total = stoi(matches[4]);

        if (curr_boy + curr_girl != curr_total)
            cerr << "Wrong children number in line #" << linenum << '\n';

        if (line[0] != prevLine[0]) {

            if (linenum != 1) out << prevLine[0] << "\t\t" << accumBoys << "\t\t"
                << accumGirls << "\t\t" << accumTot << '\n';
            accumBoys = curr_boy;
            accumGirls = curr_girl;
            accumTot = curr_total;

        }

        else if (line[0] == prevLine[0]) {

            accumBoys += curr_boy;
            accumGirls += curr_girl;
            accumTot += curr_total;
        }


        if (EOF && curr_boy == boys && curr_girl == girls) { out << line; return 0; } //this works on GCC
        //if (in.eof() && curr_boy == boys && curr_girl == girls) { out << line; return 0; } <= this works on VS 2015


        boys += curr_boy;
        girls += curr_girl;
        prevLine = line;
    }
    cerr << "Somehow the program didn't manage to complete its task :(.\n";
    return 1;
}
int main()
{
    ex10();
}

school.txt 文件的文本 KLASSE DRENGE PIGER ELEVER 0A 12 11 23 1A 7 8 15 1B 4 11 15 2A 10 13 23 3A 10 12 22 4A 7 7 14 4B 10 5 15 5A 19 8 27 6A 10 9 19 6B 9 10 19 7A 7 19 26 7G 3 5 8 7I 7 3 10 8A 10 16 26 9A 12 15 27 0MO 3 2 5 0P1 1 1 2 0P2 0 5 5 10B 4 4 8 10CE 0 1 1 1MO 8 5 13 2CE 8 5 13 3DCE 3 3 6 4MO 4 1 5 6CE 3 4 7 8CE 4 4 8 9CE 4 9 13 REST 5 6 11 Alle klasser 184 202 386

【问题讨论】:

  • 如果没有实际看到您的程序,我们无法判断为什么您的程序无法运行。请发布minimal reproducible example,其中包含我们重现问题所需的所有内容。
  • 如果(EOF)?真的吗 ? EOF 是一个常数。
  • @UmNyobe 实际上,如果只有if (curr_boy == boys &amp;&amp; curr_girl == girls) 而没有eof()EOF,则代码编译并工作。我只是不明白为什么在GCC上编译代码时eof()不起作用

标签: c++ visual-studio gcc ifstream


【解决方案1】:

EOF 是一个常量整数的宏,所以

 if (EOF && curr_boy == boys && curr_girl == girls)

正在“工作”。它只是没有按照您的预期进行,即检查文件结尾。

只有在 io 操作失败时才应该使用eof()doc 规定

std::basic_ios::eof 只报告由 most 设置的流状态 最近的 I/O 操作。它不检查关联的数据源。例如,如果最近的 I/O 是 get(),它返回文件的最后一个字节,则 eof() 返回 falsenext get() 无法读取任何内容并设置 eofbit。只有这样 eof() 才会返回 true

在你的代码中你有

while (getline(in, line)) {
   ...
   if (in.eof())
   ...
}

预期的行为是 GCC 的行为之一。要知道您在文件的末尾,您应该尝试进一步阅读。这是与

类似的问题
while (!in.eof()) {
   ...
   getline(in, line)
   ...
}

您应该将 curr_boy 和条件移出 while 循环并消除 eof 测试

int curr_boy = 0;
int curr_girl = 0;
while (getline(in, line)) {
}

if (curr_boy == boys && curr_girl == girls) { out << line; return 0; }

【讨论】:

  • 但是if (curr_boy == boys &amp;&amp; curr_girl == girls) 不会产生错误——因为变量curr_boycurr_girl 是在其中声明的。当我按照您的建议将它放在循环之外并修改为if(in.eof()) { out &lt;&lt; prevLine; return 0; } 时,它起作用了。但是现在我更迷惑了:Visual Studio 怎么能让代码在 Windows 上正常运行?!
  • 不清楚,但是你必须将 curr 变量移到外面。当有 eof 时,循环大部分时间都会终止。但是您必须执行会导致 eof 的 getline。这就是为什么 eof 在循环之外工作而不应该在循环内部工作的原因。现在 Visual Studio 以不严格遵守标准而闻名。可能是VS中的一个bug。
【解决方案2】:

您是否在相同的操作系统中使用相同的文件?

如果getline 函数在看到'\n' 之前到达文件末尾,它将设置eof 标志。这只会发生在文件的最后一行。

您可能应该将结束测试移动到 while 循环之外,我们知道当最新的 getline 未能读取另一行时,我们已经到达文件末尾。 p>

【讨论】:

  • school.txt 文件在两种情况下都是相同的。表格的最后一行不以 '\n' 结尾。
  • 这就是我询问操作系统的原因。例如,如果您在 Cygwin 下运行,则可以配置为文本文件中的行尾选择 Windows 或 Linux 规则。那可能会有所作为。无论如何,为什么不直接阅读,直到没有更多的行,然后你知道你在最后。
  • 我在 Ubuntu 15 上使用 GCC 编译的可执行文件;我在 Windows 7 上使用的 VS 编译的那个。在 Windows 上的那个没有这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-24
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
  • 2020-12-15
相关资源
最近更新 更多