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
我知道 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