C 中 cin.ignore() 的等价物是什么?

Mer*_*lli 1 c c++ stdin stdio cin

我知道 C++ 流函数是建立在 C 的stdio库之上的。

我必须在 C 中做什么才能获得与 相同的结果cin.ignore(n)
例如,我应该使用stdio函数fseek(stdin, n, 0)还是使用其他方法cin.ignore

Kam*_*Cuk 5

不,那里没有。但是让我们看看幕后会发生什么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) );
    ...
Run Code Online (Sandbox Code Playgroud)

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()).
Run Code Online (Sandbox Code Playgroud)

所以我们可以简单地推断出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_++);
}
Run Code Online (Sandbox Code Playgroud)

所以if (__ninp_ == __einp_)在做一些内部缓冲streambuf对象,而不是打电话uflow(),如果有在我们的缓冲区已经缓冲的角色。__ninp__每次读取后指针 get 都会增加,那必须是它。uflow()__stdinbuf : public basic_streambuf< .... >, 从__std_stream 重载

template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::uflow()
{
    return __getchar(true);
}
Run Code Online (Sandbox Code Playgroud)

噗,我们去__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();
    ...
}
Run Code Online (Sandbox Code Playgroud)

让我们从头开始:

  • 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__)so 可能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;
    }
}
Run Code Online (Sandbox Code Playgroud)