2016-03-07 2 views
0

Программа, которая работает очень хорошо на моей системе freeBSD, терпит неудачу, когда я ее создаю на окнах (Visual Studio 15). Он переходит в бесконечный цикл здесь:Почему fgetc перемещает указатель позиции файла назад?

//... 
while (1) { 
    if ('@' == fgetc(f)) { 
     // we do some stuff here. irrelevant for stackoverflow question 
     break; 
    }   
    fseek(f, -1, SEEK_CUR);   
    if (0 != fseek(f, -1, SEEK_CUR)) { 
     // Beginning of file. 
     break; 
    } 
} 
//... 

На ближайшем рассмотрении (добавив кучу fgetpos() - звонки) Я считаю, что fgetc перемещает указатель положения файла назад. Таким образом, он пропускает начало файла и некоторые «@», если они не находятся в позиции с несколькими позициями с конца.

Я заметил, что это только тогда, когда сложилось, файл е открыт с

fopen(filename, "a+"); 
//text mode read/append 

Когда я изменить его на

fopen(filename, "ab+"); 
//binary mode read/append 

тогда все работает, как ожидалось. Я думаю, что для моего кода безопасно использовать бинарный режим все время. Осталось два вопроса:

  • Есть ли причины, которые стоят против двоичного режима?
  • Какая обманка с неправильным направлением в текстовом режиме?
+2

Можете ли вы разместить [MCVE] (http://stackoverflow.com/help/mcve), пожалуйста? –

+1

При открытии файла в текстовом режиме есть некоторые переводы символов, которые могут произойти, особенно в новой строке в Windows - '' \ r \ n "', и при чтении он переводится в обычный' '\ n''. В Unix-системах, таких как строки новой строки BSD, существует только один '' \ n ", поэтому в таких системах перевод не выполняется. Я не знаю, объясняет ли это ваш вопрос. –

+0

«Есть ли причины, которые стоят против двоичного режима?» - На самом деле, есть много чего сказать в режиме * text * ... – DevSolar

ответ

2

Цитирование С11 7.21.9.2fseek функции:

Для текстового потока, либо смещение должно быть равно нулю, или смещение должно быть значение, возвращаемое ранней успешного вызова ftell в потоке, связанном с одним и тем же файлом и откуда должен быть SEEK_SET.

Вызов fseek откуда с аргументом SEEK_CUR на открытом потоке в текстовом режиме не распространяется на C стандарта. Открытие файла в двоичном режиме кажется намного лучшим вариантом.

Значение, возвращаемое fgetpos(), может не иметь смысла в качестве смещения в файле, оно предназначено только для аргумента fsetpos().

Как общее замечание, вы должны попробовать и изменить свои алгоритмы, чтобы не полагаться на обратные попытки в потоке, особенно полагаясь на fseek(). Ошибки кажутся ненадежными. Вместо этого сохраните позицию перед fgetc() с ftell() или fgetpos() и восстановите ее, если необходимо, с помощью fseek(pos, SEEK_SET, fp) или fsetpos().