使用 Windows 控制台时,getline() 在到达 EOF 时是否总是切换 failbit?

Does getline() always toggle the failbit when it reaches EOF when using Windows console?

提问人:user589321 提问时间:3/4/2022 最后编辑:user589321 更新时间:3/4/2022 访问量:61

问:

根据我阅读的帖子和我自己的测试,要在 Windows 终端中发送 EOF 字符,用户必须在自己的行上键入 + 并按 Enter。例如,示例 1 发送 EOF,但示例 2 不发送:CtrlZ

示例 1:

this is a test
of EOF in Windows
^Z

示例 2:

this is a test
of EOF in Windows^Z

示例 1 将切换 和 何时调用。我一直在试图弄清楚如何在不切换 .为了更好地理解发生了什么,我检查了 MSVC 中的源代码:failbiteofbitgetlineeofbitfailbitgetline

// FUNCTION TEMPLATE getline
template <class _Elem, class _Traits, class _Alloc>
basic_istream<_Elem, _Traits>& getline(basic_istream<_Elem, _Traits>&& _Istr,
    basic_string<_Elem, _Traits, _Alloc>& _Str,
    const _Elem _Delim) { // get characters into string, discard delimiter
    using _Myis = basic_istream<_Elem, _Traits>;

    typename _Myis::iostate _State = _Myis::goodbit;
    bool _Changed                  = false;
    const typename _Myis::sentry _Ok(_Istr, true);

    if (_Ok) { // state okay, extract characters
        _TRY_IO_BEGIN
        _Str.erase();
        const typename _Traits::int_type _Metadelim = _Traits::to_int_type(_Delim);
        typename _Traits::int_type _Meta            = _Istr.rdbuf()->sgetc();

        for (;; _Meta = _Istr.rdbuf()->snextc()) {
            if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { // end of file, quit
                _State |= _Myis::eofbit;
                break;
            } else if (_Traits::eq_int_type(_Meta, _Metadelim)) { // got a delimiter, discard it and quit
                _Changed = true;
                _Istr.rdbuf()->sbumpc();
                break;
            } else if (_Str.max_size() <= _Str.size()) { // string too large, quit
                _State |= _Myis::failbit;
                break;
            } else { // got a character, add it to string
                _Str += _Traits::to_char_type(_Meta);
                _Changed = true;
            }
        }
        _CATCH_IO_(_Myis, _Istr)
    }

    if (!_Changed) {
        _State |= _Myis::failbit;
    }

    _Istr.setstate(_State);
    return _Istr;
}

在示例 1 中,当您第三次调用时,函数必须以 because is on its own line 终止。这意味着 failbit 将在此处设置:getline()_Changed = false;^Z

    if (!_Changed) {
        _State |= _Myis::failbit;
    }

与示例 2 一样,您不能在导致 的行中发送 EOF。这是因为分隔符会导致您在未到达 EOF 的情况下中断,并且 EOF 不能与 Windows 控制台中的非 EOF、非分隔符在同一行上发送。_Changed = true;for (;; _Meta = _Istr.rdbuf()->snextc()) {

我的问题是:您可以使用 getline(std::cin, inp_str) 切换 std::cin eofbit 并通过 Windows 终端接口而不切换 std::cin failbit 吗?

编辑

此代码演示了上述行为。

#include <iostream>
#include <string>

int main() {

    while (!std::cin.eof()) {

        std::string next_line;
        std::getline(std::cin, next_line);

        if (std::cin.eof()) {
            std::cout << "EOF reached\n";
        }

        if (!std::cin) {
            std::cout << "failbit set";
            return 0;
        }

    }
    return 0;
}

以示例 1 作为输入,此代码以 both 和 set 结尾。eofbitfailbit

使用示例 2 作为输入,此代码不会终止。

我这里有第二个密切相关的问题:

Ctrl + Z 在 Windows 终端中是如何解释的?

C++ Windows CIN EOF GetLine

评论

0赞 Eljay 3/4/2022
您是否从重定向到正在运行的可执行文件中提供此输入流?或者您是手动逐行输入此信息?如果是后者,则该行为在到达正在运行的程序之前会受到终端(或 CMD shell)的读取行的影响。
0赞 user589321 3/4/2022
@Eljay在终端中手动输入它(Microsoft Visual Studio 调试控制台)
0赞 Eljay 3/4/2022
Microsoft Visual Studio 调试控制台可能在一种情况下吃掉字符,并在另一种情况下传递它。

答: 暂无答案