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

What's the equivalent of cin.ignore() in C?

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

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

不,没有。但让我们看看幕后发生的事情 cin.ignore()。让我们以 llvm libcxx sources 为例,我发现它们比 gcc 的更快。

extern istream cin; is in iostream, but it is initialized on application startup in 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. It's pretty simple, first we check if the user wants to clean all chars from the stream or just some of them (if (__n == numeric_limits<streamsize>::max())). Then the function calls this->rdbuf()->sbumpc() in a loop predefined amount of counts (or endless, in case __n is equal to numeric_limits<steramsize::max()). We can find sbumpc() to be a member of std::basic_streambuf, from cppreference中找到:

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() returns句柄到__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__ get 指针在每次读取后递增,一定是这样。 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;
    }
}

另外

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

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