C 中的 cin.ignore() 相当于什么?

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

我知道 C++ 流函数是构建在 C 的

stdio
库之上的。

我必须在 C 中做什么才能得到与

cin.ignore(n)
相同的结果?
例如,我应该使用
stdio
函数
fseek(stdin, n, 0)
还是
cin.ignore
正在使用其他方法?

c++ c stdin cin stdio
3个回答
6
投票

不,没有。但让我们看看幕后发生的事情

cin.ignore()
。让我们看 llvm libcxx 源代码,我发现它们比 gcc 的浏览速度更快。

extern istream cin; 位于 iostream 中,但它是在应用程序启动时在 iostream.cpp 中使用静态分配的缓冲区和从旧的“旧”构建的 __stdoutbuf 对象进行初始化的

FILE *
stdin
:

_ALIGNAS_TYPE (istream) char cin [sizeof(istream)];
ios_base::Init::Init()  {
    istream* cin_ptr  = ::new(cin)  istream(::new(__cin)  __stdinbuf <char>(stdin) );
    ...

istream::ignore()
功能可以在istraem中找到。这非常简单,首先我们检查用户是否想要清除流中的所有字符或仅清除其中的一些字符(
if (__n == numeric_limits<streamsize>::max())
)。然后,该函数在循环中调用
this->rdbuf()->sbumpc()
预定义的计数量(或无限循环,如果
__n
等于
numeric_limits<steramsize::max()
)。我们可以从
cppreference
中发现
sbumpc()
std::basic_streambuf 的成员:

int_type sbumpc();
Reads one character and advances the input sequence by one character.

If the input sequence read position is not available, returns uflow(). Otherwise returns Traits::to_int_type(*gptr()).

因此我们可以简单地推断出

this->rdbuf()
返回
__stdinbuf<char>(stdin)
的句柄。在
cin::ignore
函数中,对
__stdinbuf<char>(stdin)::sbumpc()
的调用被多次调用,我们想忽略多少个字符。那么我们就去
sbumpc()
吧!首先我们来看看streambuf

int_type sbumpc() {
    if (__ninp_ == __einp_)
        return uflow();
    return traits_type::to_int_type(*__ninp_++);
}

因此

if (__ninp_ == __einp_)
正在
streambuf
对象中进行一些内部缓冲,如果缓冲区中已经有缓冲的字符,则不会调用
uflow()
__ninp__
指针在每次读取后都会递增,这一定是这样。
uflow()
__stdinbuf : public basic_streambuf< .... >
重载,来自 __std_stream:

template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::uflow()
{
    return __getchar(true);
}

噗,我们去

__getchar
看看
true
参数是什么。它位于 __std_stream 的正下方。
这是一个很长的函数,具有主要功能,负责一些缓冲。但我们可以立即发现这个函数的核心:

template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::__getchar(bool __consume) {
    ....
        int __c = getc(__file_);
        if (__c == EOF)
            return traits_type::eof();
    ...
}

让我们从头开始吧:

  • cin
    是一个
    istraem
    对象,并从
    __stdinbuf<char>(stdin)
  • 初始化
  • istream::ignore()
    调用
    basic_streambuf::sbumpc()
    预定义的次数,可能是在使用
    stdin
  • 初始化的对象上
  • basic_streambuf::sbumpc()
    负责一些缓冲,如果缓冲区为空,则调用 basic_streambuf::
    uflow()
  • basic_streambuf::uflow()
    __stdinbuf::uflos()
    过载并调用
    __stdinbuf::__getchar()
  • __sinbuf::__getchar()
    调用
    getc(__file__)
    ,因此可能
    getc(stdin)
    从流中读取一个字符

总结一下:

void stdin_ignore(size_t n, int delim)
{
    while (n--) {
        const int c = getc(stdin);
        if (c == EOF)
           break;
        if (delim != EOF && delim == c) {
           break;
    }
}

2
投票

另外

scanf("%*[^\n]\n"); // Ignores a line

scanf("%*s"); // Ignores one string

0
投票

我知道这个问题发布已经有一段时间了,但这个解决方案似乎可以在 Linux、Mac OS 和 Windows(包括 MSVC)之间移植。如果您试图让用户输入数字,而他们不小心输入了 123a45 之类的内容,则此后的任何数字或字符串/字符输入请求都将被跳过,因为“a45”仍将位于标准输入“缓冲区”中。要解决此问题,请查看以下示例:

char someCString[64];
const int LENGTHOFCSTRING = 64;
fgets(someCString, LENGTHOFCSTRING, stdin);

这将从 stdin 读取所有数据(最多 64 个字符),包括 ' ',并将其放入 someCString 数组中。如前所述,您还可以创建一个函数 (stdin_ignore),它一次执行一个字符,对 C 字符串的长度没有限制。

© www.soinside.com 2019 - 2024. All rights reserved.