Что эквивалентно cin.ignore () в C? - PullRequest
0 голосов
/ 29 октября 2018

Я понимаю, что потоковые функции C ++ построены поверх библиотеки stdio C.

Что мне нужно сделать в C, чтобы получить тот же результат, что и cin.ignore(n)?
Например, я должен использовать stdio function fseek(stdin, n, 0) или есть какой-то другой метод, который cin.ignore использует?

1 Ответ

0 голосов
/ 29 октября 2018

Нет, нет. Но давайте посмотрим, что происходит за занавесом под названием 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) );
    ...

Функцию istream::ignore() можно найти в istraem . Это довольно просто, сначала мы проверяем, хочет ли пользователь удалить все символы из потока или только некоторые из них (if (__n == numeric_limits<streamsize>::max())). Затем функция вызывает в цикле this->rdbuf()->sbumpc() заранее определенное количество отсчетов (или бесконечное, если __n равно numeric_limits<steramsize::max()). Мы можем найти sbumpc() членом std::basic_streambuf, с 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() возвращает дескриптор __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;
    }
}
...