I understand that C++ stream functions are built on top of C's stdio library.
What do I have to do in C to get the same result as cin.ignore(n)?
For example, should I use stdio function fseek(stdin, n, 0) or is there some other method that cin.ignore is using?
No, there is not. But let's look what happens behind the curtain called cin.ignore(). Let's take llvm libcxx sources, I find them faster to look through then gcc's.
The extern istream cin; is in iostream, but it is initialized on application startup in iostream.cpp using statically allocated buffer and __stdoutbuf object constructed from the good' old' FILE * stdin:
_ALIGNAS_TYPE (istream) char cin [sizeof(istream)];
ios_base::Init::Init() {
istream* cin_ptr = ::new(cin) istream(::new(__cin) __stdinbuf <char>(stdin) );
...
The istream::ignore() function can be found in 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()).
So we can simply deduce that this->rdbuf() returns handle to __stdinbuf<char>(stdin). In the cin::ignore function the call to __stdinbuf<char>(stdin)::sbumpc() is made that many times, as many characters we want to ignore. So let's go to sbumpc()! First let's take a look at streambuf:
int_type sbumpc() {
if (__ninp_ == __einp_)
return uflow();
return traits_type::to_int_type(*__ninp_++);
}
So if (__ninp_ == __einp_) is doing some internal buffering in streambuf object, not to call uflow() if there are already buffered characters in our buffer. __ninp__ pointer get's incremented after each read, that must be it. uflow() is overloaded by __stdinbuf : public basic_streambuf< .... >, from __std_stream:
template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::uflow()
{
return __getchar(true);
}
Puff, let's go to __getchar and find out what the true parameter is. It's right below in __std_stream.
It's a long function, with the main functionality, which takes care of some buffering. But we can spot the hearth of this function right away:
template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::__getchar(bool __consume) {
....
int __c = getc(__file_);
if (__c == EOF)
return traits_type::eof();
...
}
Let's go from the beginning:
cin is an istraem object and is initialized from __stdinbuf<char>(stdin)istream::ignore() calls basic_streambuf::sbumpc() predefined number of times, probably on an object initalized using stdinbasic_streambuf::sbumpc() takes care of some bufering and calls basic_streambuf::uflow() if the buffer is empty.basic_streambuf::uflow() is overloaded by __stdinbuf::uflos() and calls __stdinbuf::__getchar()__sinbuf::__getchar() calls getc(__file__) so probably getc(stdin) to read one character from the streamTo sumarize:
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;
}
}