Повторное использование std :: cin после употребления EOF - PullRequest
0 голосов
/ 14 сентября 2018

Команда unix wc обладает следующими функциями:

$ wc - - -
aaa bbb ccc<EOF>
0 3 11 -
aaa bbb ccc<EOF>
0 3 11 -
aaa bbb ccc<EOF>
0 3 11 -
0 9 33 total

Каждый <EOF> обозначает последовательность клавиш <C-d>, которая вводит EOF в стандартный ввод. Затем wc сможет подобрать это EOF.

Я пытаюсь реализовать это в C ++. Распространенным предложением является комбинация clear() и ignore().

char c;
while (std::cin >> c) { ... }

std::cin.clear();
std::cin.ignore();

while (std::cin >> c) { /* never executed */ }

Я также пробовал std::cin.peekg(std::cin.beg), что тоже не работает.

1 Ответ

0 голосов
/ 18 сентября 2018

С помощью пациента Дэвиса я узнал разницу между печатным вводом, завершенным с помощью Ctrl + D , и документом, о котором я не знал.(Моя дань уважения Дэвису Херрингу.)

Однажды я получил его, остальное в C ++ было довольно простым, как показано в моем MCVE .

line-count.cc:

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

unsigned process(const std::string &fileName, std::istream &in)
{
  unsigned nLines = 0;
  if (in.bad()) {
    std::cerr << "ERROR: Cannot open '" << fileName << "'!\n";
    return 0;
  }
  for (std::string buffer; std::getline(in, buffer); ++nLines);
  std::cout << "File: '" << fileName << "', " << nLines << " counted.\n";
  return nLines;
}

int main(int argc, char **argv)
{
  unsigned nLines = 0;
  for (int i = 1; i < argc; ++i) {
    const std::string arg = argv[i];
    if (arg == "-") {
      nLines += process(arg, std::cin);
      std::cin.clear();
    } else {
      std::ifstream fIn(arg.c_str());
      nLines += process(arg, fIn);
    }
  }
  std::cout << "Total: " << nLines << " counted.\n";
  return 0;
}

Скомпилировано и протестировано в cygwin64 :

$ g++ -std=c++11 -o line-count line-count.cc

$ ./line-count line-count.cc - line-count.cc -
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
Total: 70 counted.

$

Итак, это действительно трюк с std::cin.clear(), который сбрасывает флаг EOF ввходной поток и делает возможным повторное чтение с /dev/stdin.

. В случае OP, std::cin.ignore() после std::cin.clear() ИМХО неверно.Он отбрасывает первый символ вновь включенного стандартного ввода, что делает следующую обработку неправильной (не считая первого символа).

Дэвис (снова) дал краткое, но очевидное объяснение, которое я даю своими словами:

При Ctrl D стандартный вход получает EOF при следующей попытке чтения;и запоминает его во внутренних флагах.Тем не менее, флаг можно сбросить.Если больше нет ввода, следующая попытка чтения потерпит неудачу, но в противном случае ввод можно просто продолжить.

Может быть, стоит подчеркнуть внутренний флаг EOF в std::ios.Без std::cin.clear() попытка чтения потерпит неудачу, даже если будет доступно больше ввода.Пока внутренние std::stream флаги не приводят к хорошему состоянию, попытка чтения не будет выполняться на более низком уровне, даже если это может быть успешным.

...