【问题标题】:What's the equivalent of cin.ignore() in C?C 中 cin.ignore() 的等价物是什么?
【发布时间】:2018-10-29 00:34:08
【问题描述】:

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

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

【问题讨论】:

  • 不,C++ 流函数不是建立在 C 的 stdio 库之上的。 C 中没有与ignore() 等价的东西。您必须自己做,一次使用getc() 读取一个字符,直到您读取终止字符,遇到EOF,或读取指定数量的字符。
  • 你理解错了。 C++ 流函数是自己构建的。你从哪里得到这个假设?
  • @LuisColorado,阅读问题的答案。在那里你可以看到cin.ignore 在后台调用getc
  • @Getfree,这不是保证,实现可以不这样做,它们可以完全基于新的实现。
  • @LuisColorado,我不是在谈论标准保证什么,而是在实践中会发生什么。 iostream 实现(不是全部)建立在 stdio 之上。

标签: c++ c stdin cin stdio


【解决方案1】:

不,没有。但让我们看看名为cin.ignore() 的幕后发生了什么。让我们以llvm libcxx sources 为例,我发现它们比 gcc 的浏览速度更快。

extern istream cin; 在 iostream 中,但它在 iostream.cpp 中的应用程序启动时使用静态分配的缓冲区和从良好的“旧”FILE *stdin 构造的 __stdoutbuf 对象进行初始化:

_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&lt;streamsize&gt;::max()))。然后函数在循环中调用this-&gt;rdbuf()-&gt;sbumpc() 预定义的计数数量(或无限循环,以防__n 等于numeric_limits&lt;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-&gt;rdbuf() 将句柄返回到__stdinbuf&lt;char&gt;(stdin)。在cin::ignore 函数中,对__stdinbuf&lt;char&gt;(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&lt; .... &gt; 重载,来自__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&lt;char&gt;(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
    

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 2014-05-08
      • 2023-03-30
      • 2010-09-17
      • 2011-07-26
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多