Поведение MacOS правильное. В соответствии со стандартом C & gt; 7.21.7.1/3 (библиотечная функция fgetc
) указание конца файла является липким; как только fgetc
видит EOF, он должен установить индикатор конца файла, который вызовет последующие вызовы, возвращающие EOF
, пока индикатор конца файла не будет очищен, например, с clearerr()
:
Если для конца потока установлен индикатор конца файла или если поток находится в конце конца файла, для конца потока установлен индикатор конца файла, а функция fgetc возвращает EOF. В противном случае функция fgetc возвращает следующий символ из входного потока, на который указывает stream. Если происходит ошибка чтения, устанавливается индикатор ошибки для потока, и функция fgetc возвращает EOF.
Поскольку предполагается, что другие функции ввода, в том числе scanf
, будут действовать так, как если бы они были реализованы при повторных вызовах fgetc
, EOF также должен быть привязан к ним. Если вы хотите продолжить чтение после получения возврата EOF, вам следует вызвать clearerr()
в потоке. (Или что-то еще, что сбрасывает индикатор, например seek()
.)
В течение многих лет реализация стандартной библиотеки C на языке Gnu не следовала стандарту. Он только сообщал об EOF один раз, оставляя следующий fgetc
ждать большего ввода на устройствах, таких как терминалы и каналы. Ошибка, о которой сообщалось в 2006 году, была , окончательно исправлена в версии 2.28 , выпущенной в августе 2018 года, хотя она еще может не входить в дистрибутив Centos.
[ Примечание. В этом ответе содержится более продолжительная дискуссия об этом поведении, в том числе устаревший (мною) и некоторые ссылки на исторические дискуссии по этой проблеме. ]
В любом случае, всегда было ясно, что переносимый код должен вызывать clearerr()
, поскольку реализации стандартных библиотек, основанные на BSD (включая MacOS), следуют стандарту, указанному выше.