Как стать автором
Обновить

Комментарии 63

Понятно, что это копи-паста. Но статья откровенно слабенькая, и не несет в себе всей истины о EOF. Не увидел акцентов на граблях его применения. В основном приведены доказательства отсутствия символа EOF в разных вариациях.
Как по мне — отличная статья, чтобы кидать ссылку в ответ тем, кто говорит что-то типа «теперь нажмите ctrl-d, чтобы ввести символ конца файла».
Однако, данный ввод будет обработан не самим приложением, а операционной системой, я так понимаю? А в приложении это приведёт к тому, что вызов getchar() вернёт EOF? И что будет, если запайпить файл, содержащий символ 0x04 на вход какой-либо программы? Это ведь не будет обработано так же?

Да, не будет, потому как поток-из-файла не то же самое, что поток-из-TTY. 0х04 спокойно пролезет в поток, а EOF будет выдан по окончанию передачи всех байт файла.

char — целочисленный, а EOF определяется как -1, то есть FF. Соответственно, во время оно при считывании файла c помощью getc всё прекрасно остановливалось, если в файле был этот символ. Символом он является, потому что является возможным значением для char.
getc() возвращает int, EOF (-1) и это не 0xff. Как себя будет вести ваша конструкция при чтении бинарного файла?
getc() возвращает int, EOF (-1) и это не 0xff.
при считывании символа 0xFF функция возвращала именно -1, а не 0x000000ff
Как себя будет вести ваша конструкция при чтении бинарного файла?
а)Это не моя конструкция, б)getc() считывает символ 0xff. Возвращает -1. Типичный цикл считывания при этом прерывался, так что файл до физического конца не считывался. Это было одной из типичных ошибок и можно найти уйму рекомендаций не использовать эту функцию для работы с файлами, а только для чтения с консоли.

Это в какой ОС?
У меня man getc говорит "returns it as an unsigned char cast to an int".

Вероятно имеется в виду поведение, наподобие описанного в
man7.org/linux/man-pages/man3/getc.3p.html
If the integer value returned by getc() is stored into a variable of
type char and then compared against the integer constant EOF, the
comparison may never succeed, because sign-extension of a variable of
type char on widening to integer is implementation-defined.


Тоже в своё время часто встречал, на Западе часто экономили на «unsigned » :)
Это, видимо, потому что код программы некорректный
конечно
EOF — это символ, который генерируется нажатием CTRL+Z.
В MS DOS он служил флагом окончания текстового файла. Кстати, если что-то дописать после этого символа, DOS не выводила эту дописку командой «type».

C:\> copy con myfile.txt
blah-blah-blah
<CTRL+Z>
C:\>

И не только в DOS, а во многих старых системах, RSX-11, например. Собственно везде, где работали с перфолентами и перфокартами.

Проблема была простая — как отличить обрыв перфоленты от её штатного конца? Вот для решения этой проблемы и придумали EOF. Ещё смешнее он выглядел на перфоркарте — это была отдельная карта. Самый смешной вариант для «отдельной перфокарты» — это ГОСТ 23057-78, стандарт FORTRAN: Заключительной строкой называется такая строка, которая в позициях 1-6 содержит пробелы, а в позициях 7-72 пробелы и буквы E, N и D.
Тепреь я хоть понял, откуда, вообще, пошла эта тема и эта дискуссия. Спасибо, ваш один комментарий ценнее всей статьи!
Хе-хе, а вот в CP/M-80 был именно что символ EOF. Потому как файлы были кратны 128 байтам.

И то ли сама MS-DOS, то ли некоторые программы более-менее корректно его обрабатывали

Насколько я помню, на уровне стандартных библиотек (если открывать файл, как текстовый – дальше EOF не читался)

А под DOS, емнип, были текстовые редакторы, которые в обычный текстовый файл после символа EOF записывали свою служебную информацию. Получалось, что команда type выдавала файл без неё, а редактор использовал.
на уровне функции getc(), если быть точным.
В Си — да, в Паскале – реализация операторов read/readln, в других языках ещё что-то…
А при написании под CP/M-80 на ассемблере (PL/M почему-то мне так и не попался) надо было всё делать руками :-)
А при написании под CP/M-80 на ассемблере
Извините, не напугали :-)
На ассемблере — о каких таких стоп-символах вообще может речь?

Жалко, плюсик поставить не могу)


На ассемблере – ну, примерно о тех же, что на Си, только "закат солнца вручную". Т.е. обрабатывать их самому в соответствии с рекомендациями + не забывать о крайних случаях (сегодня освежал в памяти особенности работы с файлами в CP/M – наткнулся на обсуждение, нужен ли EOF, если размер файла кратен 128 байтам… Оказывается, не нужен)

Если бы автор открыл файл в текстовом режиме под Windows*, то он мог бы обнаружить, что символ с кодом 0x1a вполне себе интерпретируется как признак конца файла.
Управляющие символы ASCII
Номер Английское название Русское название
1A SUBSTITUTE символ замены
Привет от Q[uick]BASIC. Откройте файл в текстовом режиме и EOF вполне себе станет символом.
В чём отличие прочитанного байта 0xFF и EOF?
Зависит от того, с чем его сравнить. Если с char, — то от реализации. В стандарте не указана ни размерность char, ни его знаковость.
Это называется здравствуйте грабли.
Изначально getc() возвращает тип INT, и при этом символы кодируются беззнаковым unsigned char (byte).
Int EOF == ( -1 ) совсем не равен 0xFF.
А вот если считывать getc() в char, и при этом не читать варнинги при компиляции, получим EOF == 0xFF
А вот если считывать getc() в char, и при этом не читать варнинги при компиляции, получим EOF == 0xFF

А если собирать под ARM, то бесконечный цикл (char == unsigned char, unsigned char != -1).

Байт 0xFF для Windows-1251 это буква я.
Вот так легко и просто можно написать программу, не умеющую некоторые буквы в некоторых языках. Как старинный софт для FIDO, не умеющий букву Н ;)
Вспомнилось «На FTP сервере окончательно исправлена проблема с буквой '' теперь вы можете заливать файлы с названими с буквой ''»
И что-то такое (с буквой «я») совершенно точно попадалось, кажется, у Borland C++ с ней были проблемы.

Telnet в кои8 иногда рвал соединениЯ, если в стриме попадалась буква Я. Маялись админы русскоязычных мадов, в частности "Мир Мерлина". Да, вероятно, проблема на стороне программирования лежала именно в слепом конвертировании getc() в signed char, скажем. Но пользователям видно по-другому, я тогда больше играл, чем кодил.

Просто стыдно читать, с каким пафосом автор пишет о том, чего не знает, не удосужившись прочеть даже викпедию!
Да, EOF *БЫЛ* символом конца файла, в DOS этот символ был необязательным, но поддерживался, а в CP/M, например, это вообще — единственный способ обозначения конца файла.

Неверные итоги.


  1. EOF = 0x1a (упоминалось выше в комментах), вполне существующий символ. И почему это вы его в ASCII-таблице не нашли? Update: а, его переименовали с 199х — значит "был" такой символ. В сохранившейся у меня книжке Programming for MS-DOS символ 0x1a всё ещё назывался EOF.
  2. Верно для текущей эпохи, в которой верно ещё и 3), но в общем случае неверно. DOS 5.0 (как минимум) при попытке сделать type somefile.wav, где файл — валидный WAV тех времен, выдавал на дисплей "Creative voice file" и затыкался. Побайтный анализ показывал, что после данной строки в бинарном файле шли два символа EOF, за которыми уже начинался заголовок бинарного сегмента файла. Тот же трюк использовался во многих других программах, включая, не в последнюю очередь, игру GEEKWAD, сообщавшую "хакеру" информацию "The secret codeword is CHEAT", каковое слово приводило к реакции а-ля IDDQD в Heretic'e.
  3. Сейчас — верно, но не только оно.
  4. Был такой символ. Сейчас его нет, и EOF теперь состояние потока.
Соглашусь. Особенно доставляют например вот такие «доказательства»:

>Для этого можно воспользоваться командой xxd:
Чем, простите? Прежде чем результаты команды принимать за доказательство чего-либо, нужно сначала показать, каким именно API пользуется эта команда. Кроме того, тот факт, что мы не можем прочитать этот символ из файла, вообще не означает, что этого символа нет в файле (в блоке на диске). Чтобы доказать это, нужно как минимум прочитать дисковый блок.
> приводило к реакции а-ля IDDQD в Heretic'e

Немедленное самоубийство?

В doom же

Гугл подсказывает, что всё же как в Heretic'е.


Heretic:


iddqd. Kills the player. Originally the Godmode cheat in Doom, it is a joke by the developers by making it have the opposite effect in Heretic. When entered, on the screen is displayed: "Trying to cheat, eh? Now you die!"

Geekwad:


No Fair Cheating: If you input CHEAT as a password, Cybergeek gets furious and makes the ship explode
Помню в начале 2000-х (3-4 года) за этот символ (или два, точно не помню — давно было) в PE-экзешники дописывали трек номер — чтобы потом читать его при запуске программы и отправлять на сервак для статистики — какая реклама (сайт) лучше работает для распространения. Сначала читали как бинарный файл, но позже были проблемы (уже в 2000 или xp) — считать сам себя экзешник не мог — поэтому открывали его через CreateProcessA и шагали по страницам памяти за переделы — все работало. Поэтому в «штатном» режиме чтения EOF всегда считал состоянием потока — то есть курсор чтения файла вышел за границы размера файла, и проверял это до чтения файла — достигнут ли конец файла и потом пробовал считать данные. Собственно как и константа INVALID_HANDLE_VALUE в винде по умолчанию -1, потому что handle принято считать всегда больше или равным 0, но меньше или равным максимальной разрядности, то есть те самые FF, собственно как и коды символов. А сравниваемые значения всегда приводятся к большей разрядности и получаем, что -1 никогда не будет в диапазоне 0..ff, что удобно при использовании кодов ошибок. По такой же схеме INVALID_HANDLE_VALUE равный -1 не попадающий в 0..0xFF FF FF FF. Это если про символы — но тут холивар разводить можно долго про «символ» vs «признак окончания чтения потока данных». Смотря в каком режиме и контексте используется данная аббревиатура…
В командной строке Windows выполняем:
>echo «line1» >test1.txt
>echo «line2» >test2.txt
>copy test1.txt + test2.txt > test3.txt
И смотрим test3.txt в HEX редакторе — последний символ в файле — 0x1A

Так что был такой символ, точно был. Даже вот такие рудименты от него остались.

Вау! Сто лет не видел использования copy file1+file2, а тут ещё такой сюрприз. И таки да, WS2012 — confirmed.

да, только я накосячил с перенаправлением.
Правильный вид третьей команды — вот такой
copy test1.txt + test2.txt test3.txt
там пробел должен быть а не правая угловая скобка.
Прошу прощения у всех, у кого фокус не получился

этот фокус не получился и с пробелом

стандарт С11, стр.296

7.21.1
The macros are…
EOF
which expands to an integer constant expression, with type int and a negative value, that
is returned by several functions to indicate end-of-file, that is, no more input from a
stream;

и выше, на той же странице, в пункте 2, касательно типа FILE

end-of-file
indicator that records whether the end of the file has been reached

Недавно я читал книгу «Компьютерные системы: архитектура и программирование. Взгляд программиста». Там, в главе про систему ввода-вывода Unix, авторы упомянули о том, что в конце файла нет особого символа EOF.


Ясно, что перевод/копипаст, но хотябы не поленились найти эту книгу, упомянутую главу, и бросить пруф на место, где «авторы упомянули о том, что в конце файла нет особого символа EOF.»

PS: а был еще EOL, ну там то точно символ, даже два можно!
Девиз автора статьи:
«Все, что стоит делать, стоит делать плохо — пока ты не научишься делать это хорошо».
“Anything worth doing is worth doing poorly — until you learn to do it well.”

ruslanspivak.com/pages/about
Автор сумел разжечь холивар на пустом месте в буквальном смысле этого слова.
Талантище.
Респектище.
PS. Напомнило исследование — самая короткая программа, которая завесит DOS. Оказалось — 0 байт.
Тут, опять же, можно проверить коды символов в таблице ASCII, можно взглянуть на таблицу Unicode и узнать о том, в каком диапазоне могут находиться коды символов. Мы же поступим иначе: запустим интерпретатор Python и ...

На серьёзных щах гонят какую-то дичь с доказательствами от Васи из 7 класса.

А еще есть BOF и как бы понятно, что BOF и EOF не символы, а признаки

docs.microsoft.com/ru-ru/sql/ado/reference/ado-api/bof-eof-properties-ado?view=sql-server-ver15

Тем, кто работал с файлами баз данных типа dbf, это давно известно
А есть ещё BOM. И это символ, но к статье это не имеет отношения.
Интересный факт: в ДОСе после копирования со слиянием текстовых файлов командой
copy Файл1.txt + Файл2.txt + Файл3.txt Файл123.txt в конец файла добавлялся загадочный символ: "→". Не он ли это был? :-)
он самый, см. мой коммент выше
EOF это пережиток тех времен, когда файлы считывались последовательно, символ за символом, с ленты. После появления файловых систем на дисках необходимости в нем нет, а след в API остался.
EOF это символ таблицы ASCII с кодом 0x1A (26 десятичный)
А как оно там в каких библиотеках обрабатывается — дело десятое. Их назначение как раз в том чтобы скрыть детали реализации абстракции. В конце концов таблица ASCII тоже не более чем случайная последовательность принятая в определенных протоколах для кодирования инфы. А понятие конца файла как бе универсально а посему на уровне либ от такой частности как используемая таблица кодировки зависеть не должно от слова совсем.
Эти управляющие символы ведут свои корни ещё с телетайпов и др. полумеханических машин. Коли утверждать чего нет, а чего есть надо бы посмотреть старые документы ;)
Собсна символ 26, он же 0х1A назывался (eof) © Microsoft 1985-1990
image
Т.к. абсолютное большинство ЭВМ снабжено осью от МС, то и символ правильно называть еоф, а не суб.

EOF — это непечатный непечатаемый символ.


P.S. Эпоха хайп-статей апофигевающих от непонятных нюансов в стандартах. Ждем статьи про то, что "перевод строки это не символ, но под виндой всё не так просто"

В современных *nix символ ASCII EOF(0x1A) игнорируется чуть более чем полностью. Собственно и сам символ EOF не нужен, от слова совсем.
image
И вообще, причём тут DOS / Windows / CP/M / RSX-11/ whatever? Статья про UNIX/Linux, а не вот это вот всё.
C:\> copy con 1.txt
blah
blah-blah
(<Ctrl-Z>|<Alt+026>)
1 file(s) copied
C:\>

У кого есть под рукой, на FreeDOS прокатывает?

UPD: На PC-DOS работает:
image

сишники странные…
Когда я изучал Паскаль 7, где-то вычитал, что EOF это ПРИЗНАК конца файла и я всегда eof воспринимал как флаг окончания получения данных. Если сравнить с потоком, то истинное условие равенства позиции и длины файла.
Как байт в конце файлов его не встречал и никогда не размышлял над этой глупостью.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий