- 主题:[求助]又是烦人的cin,linux和win10下结果还不一样!
从键盘向两个vector vec和vec2填充字符串的程序:
#include <iostream> // For standard streams
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
static void cin_state(void)
{
cout << "[fail,eof,bad]: ["
<< cin.fail() << cin.eof() << cin.bad()
<< "], state-good: " << cin.good() << endl;
}
static void cin_clear(void)
{
cout << "\n=>before cin.clear()";
cin_state();
cin.clear();
cout << " after cin.clear()";
cin_state();
}
int main(void)
{
std::vector<std::string> vec, vec2;
std::copy(std::istream_iterator<std::string> {std::cin},
std::istream_iterator<std::string>{},
std::back_inserter(vec));
std::copy(std::cbegin(vec),
std::cend(vec),
std::ostream_iterator<std::string>{std::cout, " "});
cin_clear();
std::copy(std::istream_iterator<std::string> {std::cin},
std::istream_iterator<std::string>{},
std::back_inserter(vec2));
return 0;
}
Win10+vs2019没有问题
Linux下vec2根本就没有机会输入,好像车子挂不上档,即使我增加std::cin.ignore()也没有用:
$ Snippets ./a.out
akdf kdfj ksdj fksdfj dsf
akdf kdfj ksdj fksdfj dsf
=>before cin.clear()[fail,eof,bad]: [110], state-good: 0
after cin.clear()[fail,eof,bad]: [000], state-good: 1
$ Snippets
--
修改:ActiveIon FROM 61.149.156.*
FROM 61.149.156.*
补上win10+vs2019的运行结果(正常):
C:\Users\92787\source\repos\books_sourcecode\Using_STL>test
skdjfskjfdlkdsaj lkjlks jd fkj ksdjf kdsjfksj kkdsjfkdsj fkj dsfkjkds fjkdsfj kjdsf kdsfj
^Z
skdjfskjfdlkdsaj lkjlks jd fkj ksdjf kdsjfksj kkdsjfkdsj fkj dsfkjkds fjkdsfj kjdsf kdsfj
=>before cin.clear()[fail,eof,bad]: [110], state-good: 0
after cin.clear()[fail,eof,bad]: [000], state-good: 1
sdf dskfj kdsfj djf kdfj kdfj kdfj
^Z
C:\Users\92787\source\repos\books_sourcecode\Using_STL>
--
FROM 61.149.156.*
这对我来说,太难了。 哭笑不得。
anyway,谢谢。
【 在 yytree 的大作中提到: 】
: Checking C runtime library
: Disassemble your code
:
--
FROM 61.149.156.*
那再想用这个cin输入,咋办?cin是单例吧。
【 在 ilovecpp 的大作中提到: 】
: linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
--
FROM 61.149.156.*
网上搜索到这段话,但不知道具体如何重新连接tty:
在无效输入后可以恢复状态:未能根据预期类型解析输入,只需设置 std:: ios_base::failbit ,这可以是 clear() . 由于不会删除导致问题的字符,因此您可能需要摆脱它(例如使用 ignore() )或以不同方式对数据进行parae .
虽然EOF也只是一个标志( std::ios_base::eofbit )清除它一般不会从已经到达流的末尾恢复 . 特定流可以具有继续读取的方式,但是在流指示符结束之后控制台很可能被断开(例如,Ctrl-D或Ctrl-Z) . 根据系统,可以创建到控制台的新连接,例如,通过打开文件流到 /dev/tty .
如果您确实想使用控制字符来指示特殊处理,请使用 tcgetattr() 和 tcsetattr() 将流设置为非规范模式 . 完成此操作后,可以看到输入的所有字符,并且可以在自定义流缓冲区中进行处理 . 我不知道如何在其他系统上做类似的事情 .
【 在 ilovecpp 的大作中提到: 】
: linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
--
FROM 61.149.156.*
感谢大家。终于搞定了
#include <iostream> // For standard streams
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
static void cin_state(void)
{
std::cout << "[fail,eof,bad]: ["
<< std::cin.fail() << std::cin.eof() << std::cin.bad()
<< "], state-good: " << std::cin.good() << std::endl;
}
static void cin_clear(void)
{
std::cout<<"\n=>before cin.clear()";
cin_state();
std::cin.clear();
std::cout << " after cin.clear()";
cin_state();
}
#include <cstdio>
#include <fstream>
int main(void)
{
std::vector<std::string> vec;
std::copy(std::istream_iterator<std::string>{std::cin},
std::istream_iterator<std::string>{},
std::back_inserter(vec));
std::copy(std::cbegin(vec),
std::cend(vec),
std::ostream_iterator<std::string>{std::cout, " "});
std::cout << std::endl;
/****
* 和Windows不同, Linux的EOF后,std::cin就不能复活了
* 因为已经和/dev/stdin文件断开了连接,只能使用ifstream重新连接。
* 而Windows的std::cin接收到EOF以后,可是使用cin.clear()重新复活
*
* 当然,Win和Linux如果发生failbit,都可以通过clear()重新复活,
* 虽然往往需要再调用ignore()来剔除缓冲区中的一些多余的字符。
*/
std::vector<std::string> vec2;
#ifdef __unix__
std::ifstream fin("/dev/stdin");
std::istream_iterator<std::string> iit{fin};
#endif
#ifdef WIN32
cin_clear();
std::istream_iterator<std::string> iit{std::cin};
#endif
std::copy(iit,
std::istream_iterator<std::string>{},
std::back_inserter(vec2));
std::copy(std::begin(vec2),
std::end(vec2),
std::ostream_iterator<std::string>{std::cout, " "});
std::cout << std::endl;
return 0;
}
/*
*
$ ./a.out
dkfj k kdfj sf dsalaskd jf
dkfj k kdfj sf dsalaskd jf
aa bb cc dd ee ff
aa bb cc dd ee ff
$
*
*/
【 在 ilovecpp 的大作中提到: 】
: linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
--
FROM 61.149.156.*
ilovecpp的建议超赞! 感谢。
按照这个思路,我的代码改为:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
using namespace std;
template <typename T>
void cin_fill(back_insert_iterator<T> bit)
{
string line;
while (true)
{
getline(cin, line);
if (!line.empty())
{
istringstream ss{line};
for (;;)
{
typename T::value_type n;
ss >> n;
if (!ss)
break;
bit=n;
}
} else break;
}
}
#include <algorithm>
int main(void)
{
{
vector<int> vec;
cin_fill(back_inserter(vec));
std::copy(std::cbegin(vec), std::cend(vec), std::ostream_iterator<int>{std::cout, " "});
std::cout << std::endl;
}
{
vector<std::string> vec;
cin_fill(back_inserter(vec));
std::copy(std::cbegin(vec), std::cend(vec), std::ostream_iterator<std::string>{std::cout, " "});
std::cout << std::endl;
}
return 0;
}
/***
12 34 56
78 q 90
12 34 56 78
^C
*/
【 在 ilovecpp 的大作中提到: 】
: 不建议把输入格式设计成这样。就像我前面说的,linux文件里没有EOF字符,你这样搞,如果输入是从文件重定向的就根本没法输入了。
: 比如,你可以用回车表示一组数据结束:
: string line;
: ...................
--
修改:ActiveIon FROM 111.201.151.*
FROM 61.149.156.*
是可以的,只是不应该这么设计。
其实一个流需要重复使用,就不应该发送EOF结束符号,而应该向ilovecpp说的那样使用“空行”来结束一次输入。linux不能复活EOF,也是这么考虑的,是正确的思路。win使用clear()来复活EOF我觉得是不对的。
linux这个行为可以扩展到socket中,socket关闭后也是不能复活的,虽然socket关闭后,read系统调用返回的不是EOF(其实为0xFF)而是0, 但道理是相通的:关闭的流就不应该被复活。
【 在 here080 的大作中提到: 】
: 可不可以不用宏?可不可以全部都使用ifstream来重新连接?
:
--
FROM 61.149.156.*