Отмена эффектов ungetc() : Как это делают fseek(),rewind() и fsetpos()? Буфер каждый раз пополняется?

Ха!! Как бы мне выразить все это в четком вопросе!! Позвольте мне попробовать:

Я знаю, что файлы, открытые с помощью fopen(), буферизуются в память. Мы используем буфер для эффективности и простоты. Во время чтения из файла содержимое файла сначала считывается в буфер, и мы читаем из этого буфера. при записи в файл содержимое сначала записывается в буфер, а затем в файл.

Но что с fseek(), fsetpos() и rewind()отбрасыванием эффекта предыдущих вызовов ungetc()? Не могли бы вы рассказать мне, как это делается? Я имею в виду, что мы открыли файл для чтения и он скопирован в буфер. Теперь с помощью ungetc() мы изменили некоторые символы в буфере. Вот что я просто не могу понять даже после долгих усилий:

  • Вот что сказано о ungetc() --"Вызов fseek, fsetpos или перемотки в потоке отбрасывает все символы, ранее помещенные в него с помощью этой функции." --Как символы, уже помещенные в буфер один из подходов заключается в том, что исходные символы, которые были удалены, «запоминаются», а каждый новый введенный символ идентифицируется и заменяется исходным символом. Но это кажется очень неэффективным. Другой вариант — загрузить копию исходный файл в буфер и поместите указатель файла в предполагаемую позицию. Какой подход из этих двух использует fseek, fsetpos или перемотка, чтобы отбросить символы, введенные с помощью ungetc()?

  • Для текстовых потоков, как наличие непрочитанных символов в потоке, символы, которые были введены с использованием ungetc(), влияют на возвращаемое значение ftell()? Меня смущает следующая строка о ftell() и ungetc() из этой ссылки о ftell(ИСТОЧНИК)

"Для текстовых потоков числовое значение может не иметь смысла, но его все же можно использовать для восстановления позиции в ту же позицию позже с помощью fseek (если есть символы, возвращенные с помощью ungetc, которые все еще ожидают чтения, поведение не определено)."

  • Сосредоточившись на последней строке вышеприведенного абзаца, какое отношение pending of being read имеет к отбрасыванию полученного "ungetc()" символа? Каждый раз, когда мы читаем символ, который был помещен в поток с помощью ungetc(), он отбрасывается после чтения?

person Thokchom    schedule 22.05.2013    source источник
comment
попробуй, напиши себе программку и посмотри что получится   -  person Peter Miehle    schedule 22.05.2013
comment
@PeterMiehle Здесь нечего попробовать. Я спрашиваю, как это делается. Это концептуальная вещь. Если у вас есть что-то конкретное, что вы предлагаете мне попробовать, дайте мне знать.   -  person Thokchom    schedule 22.05.2013
comment
написать себе небольшую программу, чтобы увидеть, это ужасный способ понять язык/библиотеку программирования, которая имеет большое количество реализаций для того, что кажется каждой известной платформой.   -  person Kaz    schedule 15.01.2014


Ответы (2)


Хорошая мысленная модель отложенного символа состоит в том, что это просто какое-то дополнительное маленькое свойство, которое свисает с объекта FILE *. Представьте, что у вас есть:

typedef struct { 
   /* ... */
   int putback_char;
   /* ... */
} FILE;

Представьте, что putback_char инициализируется значением EOF, которое указывает, что "символ возврата отсутствует", а ungetc просто сохраняет символ в этом элементе.

Представьте, что каждая операция чтения проходит через getc, а getc делает что-то вроде этого:

int getc(FILE *stream)
{
   int ret = stream->putback_char;

   if (ret != EOF) {
     stream->putback_char = EOF;
     if (__is_binary(stream))
        stream->current_position--;
     return ret;
   }

   return __internal_getc(stream); /* __internal_getc doesn't know about putback_char */
}

Функции, которые очищают откат, просто присваивают EOF putback_char.

Другими словами, возвращенный символ (а поддерживаться должен только один) на самом деле может быть миниатюрным буфером, который отделен от обычной буферизации. (Учтите, что даже небуферизованный поток поддерживает ungetc: такой поток должен куда-то поместить байт или символ.)

Относительно индикатора положения в стандарте C99 сказано следующее:

Для текстового потока значение его индикатора позиции в файле после успешного вызова функции ungetc не указывается до тех пор, пока все вытесненные символы не будут прочитаны или отброшены. Для двоичного потока его индикатор позиции в файле уменьшается при каждом успешном вызове функции ungetc; если его значение было равно нулю до вызова, то после вызова оно неопределенно. [7.19.7.11 Функция ungetc]

Таким образом, ссылка на www.cplusplus.com, которую вы используете, неверна; поведение ftell не является неопределенным, когда есть ожидающие символы, отодвинутые назад с помощью ungetc. Для текстовых потоков значение не указано. Доступ к неопределенному значению не является неопределенным поведением, поскольку неопределенное значение не может быть представлением ловушки. Неопределенное поведение существует для двоичных потоков, если возврат происходит в нулевой позиции, потому что тогда позиция становится неопределенной. Неопределенный означает, что это неуказанное значение, которое может быть представлением ловушки. Доступ к нему может остановить программу с сообщением об ошибке или вызвать другое поведение.

Лучше получить спецификации языка программирования и библиотеки из уст лошади, а не со случайных веб-сайтов.

person Kaz    schedule 14.01.2014

Давайте начнем с самого начала,

int ungetc(int c, FILE *stream);

Функция ungetc() должна поместить байт, указанный параметром c (преобразованный в беззнаковый символ), обратно во входной поток, на который указывает stream. Символ виртуально помещается обратно во входной поток, уменьшая его внутреннюю позицию в файле, как если бы предыдущий getc операция была отменена. Это влияет только на дальнейшие операции ввода в этом потоке, а не на содержимое связанного с ним физического файла, который не изменяется никакими вызовами этой функции.

int fseek(FILE *stream, long offset, int whence);

Новая позиция, измеренная в байтах от начала файла, должна быть получена путем добавления смещения к позиции, указанной параметром "откуда". Указанная точка является началом файла для SEEK_SET, текущим значением индикатора позиции файла для SEEK_CUR или концом файла для SEEK_END. будет записано позже на свое место в файле

int fsetpos(FILE *stream, const fpos_t *pos);

Функция fsetpos() устанавливает позицию файла и индикаторы состояния для потока, на который указывает stream, в соответствии со значением объекта, на который указывает pos, которое должно быть значением, полученным из более раннего вызова fgetpos() в том же потоке.

void rewind(FILE *stream);

Функция перемотки перемещает указатель файла, связанный с потоком, в начало файла. Вызов перемотки похож на

(недействительно) fseek(поток, 0L, SEEK_SET);

Итак, как вы видите, ungetc(), перемещение символов назад не изменяет файл; затрагивается только внутренняя буферизация потока, поэтому ваш второй комментарий «Другой вариант — загрузить копию исходного файла в буфер и поместить указатель файла в предполагаемую позицию» верен.

Теперь отвечая на ваш второй вопрос. Успешный промежуточный вызов (с потоком, на который указывает поток) функции позиционирования файла отбрасывает любые вытесненные символы для потока. Внешнее хранилище, соответствующее потоку, не изменилось

person Dayal rai    schedule 22.05.2013