Отмяна на ефектите на 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()-obtained"? Всеки път, когато четем знак, който е бил поставен в потока с помощта на 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 (преобразуван в неподписан char) обратно във входния поток, към който сочи stream. Символът виртуално се връща обратно във входен поток, намалявайки вътрешната му файлова позиция, както при предишен getc операцията беше отменена. Това засяга само по-нататъшните операции за въвеждане на този поток, а не съдържанието на физическия файл, свързан с него, който не се променя от никакви извиквания на тази функция.

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

Новата позиция, измерена в байтове от началото на файла, се получава чрез добавяне на отместване към позицията, посочена откъде. Посочената точка е началото на файла за SEEK_SET, текущата стойност на индикатора за файлова позиция за SEEK_CUR или края на файла за SEEK_END.fseek или изчиства всеки буфериран изход, преди да зададе позицията на файла, или го запомня, така че ще бъде записано по-късно на правилното място във файла

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

Функцията fsetpos() задава позицията на файла и индикаторите за състояние за потока, към който сочи поток, според стойността на обекта, към който сочи pos, която трябва да бъде стойност, получена от по-ранно извикване на fgetpos() на същия поток.

void rewind(FILE *stream);

Функцията за пренавиване препозиционира указателя на файла, свързан с потока, в началото на файла. Обаждането за пренавиване е подобно на

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

Така че, както виждате ungetc(), избутването на знаци не променя файла; само вътрешното буфериране за потока е засегнато. така че вторият ви коментар „Другата опция е да заредите копие на оригиналния файл в буфера и да поставите указателя на файла на желаната позиция“ е правилен.

Сега отговарям на втория ви въпрос - Успешно намесено извикване (с потока, посочен от поток) към функция за позициониране на файл отхвърля всички избутани знаци за потока. Външното хранилище, съответстващо на потока, е непроменено

person Dayal rai    schedule 22.05.2013