Cin 总是失败并且在管道之后不停止执行

问题描述 投票:0回答:1

这里是函数代码:

#include <iostream>
#include <string>
#include <limits>
#include <sstream>

using namespace std;

int main (int argc, char **argv)
{
    string StrInput;

    while (1)
    {
        cout << "Enter a string : ";
        getline(cin,StrInput);
        if(cin.fail())
        {
            cin.clear();
            cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
        else
        {
            cout << StrInput;
            
        }
    }

    return 0;
}

如果我启动我的软件:

echo "test" | ./test.exe

...它打印

test
,然后无限循环 cin.fail() 等于 1。

我想要的是,第一个循环它获取管道的值,但随后它停止并等待用户输入新字符串。 我试图寻找一个等待来更改 cin 的输入,但没有找到等待。

有人有想法吗?

c++ pipe iostream cin
1个回答
0
投票

我想要的是第一个循环它获取管道的值,但随后它停止并等待用户输入新字符串。

这个答案与上面的主题有关,如果您不知道管道到底是什么以及它是如何工作的,您应该寻求其他信息或提出新问题。

你的程序出了什么问题

在您的程序中,

std::cin
失败,因为它从管道读取
EOF
。如果你继续要求它读取,它就会永远失败。您需要做的是在
if
块之前插入一段代码:

    // Judge EOF first
    if (cin.eof()) {
      cout << "\nEOF" << endl;
      break;
    } else if (cin.fail()) {
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else {
      cout << StrInput << endl;
    }

这只会暂时修复代码。

坚持你的问题

如何检测 STDIN 的绑定位置

我们如何找出 STDIN 是绑定、管道还是键盘?在 Linux 中,您可以使用 POSIX:

#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  string str;
  cin >> str;
  cout << "read str: " << str << endl;

  if (isatty(fileno(stdin))) {
    cout << "std from keyboard" << endl;
  } else {
    cout << "std directed" << endl;
  }

  return 0;
}
❯ echo "111" | ./test
read str: 111
std directed
❯ ./test
111
read str: 111
std from keyboard

在Windows中,您可以使用Windows API:

#include <Windows.h>
#include <iostream>
#include <processenv.h>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  string str;
  cin >> str;
  cout << "read str: " << str << endl;

  DWORD file_type = GetFileType(GetStdHandle(STD_INPUT_HANDLE));

  if (file_type == FILE_TYPE_CHAR) {
    cout << "stdin from keyboard" << endl;
  } else {
    cout << "stdin directed" << endl;
  }
}

如何在管道后重新输入

如果通过管道启动进程,STDIN 会绑定到前一个进程的 STDOUT。在您的示例中,

./test.exe
的 STDIN 绑定到
echo
的 STDOUT。我们需要的是将其重新绑定到您的键盘。这是 Linux 上的代码:

#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  string input;
  bool is_pipe = false;

  if (!isatty(fileno(stdin))) {
    is_pipe = true;
  }

  // if stdin is bound to pipe
  if (is_pipe) {
    // Your pipe code here
    while (1) {
      cout << "Enter a string : ";
      getline(cin, input);
      if (cin.eof()) {
        cout << "pipeline EOF" << endl;
        break;
      } else if (cin.fail()) {
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      } else {
        cout << input << endl;
      }
    }

    // rebind stdin
    freopen("/dev/tty", "r", stdin);
    cout << "stdin rebind to keyboard" << endl;
    cin.clear();
  }

  // keyboard code here
  while (1) {
    cout << "Enter a string : ";
    getline(cin, input);
    
    if (cin.fail()) {
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else {
      cout << input << endl;
    }
  }
}
❯ echo "111" | ./test
Enter a string : 111
Enter a string : pipeline EOF
stdin rebind to keyboard
Enter a string : This is from keyboard
This is from keyboard
Enter a string : ^C
❯ ./test
Enter a string : This is from keyboard
This is from keyboard
Enter a string : ^C

并在 Windows 上使用 WinAPI:

#include <Windows.h>
#include <cstdio>
#include <fileapi.h>
#include <iostream>
#include <limits>
#include <processenv.h>
#include <string>
#include <winbase.h>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  string input;
  bool is_pipe = false;

  if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) != FILE_TYPE_CHAR) {
    is_pipe = true;
  }

  // if stdin is bound to pipe
  if (is_pipe) {
    // Your pipe code here
    while (1) {
      cout << "Enter a string : ";
      getline(cin, input);
      if (cin.eof()) {
        cout << "pipeline EOF" << endl;
        break;
      } else if (cin.fail()) {
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      } else {
        cout << input << endl;
      }
    }

    // rebind stdin
    freopen("CON", "r", stdin);
    cout << "stdin rebind to keyboard" << endl;
    cin.clear();
  }

  // keyboard code here
  while (1) {
    cout << "Enter a string : ";
    getline(cin, input);

    if (cin.fail()) {
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else {
      cout << input << endl;
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.