В текстовых файлах Windows используется последовательность байтов 0D 0A для обозначения конца строки (Unix использует только один байт, 0A).Стандартная библиотека C переводит между этой внешней кодировкой и внутренним символом «виртуальной новой строки» ('\n'
), который использует C.
То есть, когда программа на C, работающая в Windows, записывает '\n'
в текстовый поток, он переводится в 0D 0A.Обратная операция происходит на входе.Поскольку '\n'
является действительным значением char
(обычно 10
), другие байты могут быть неверно истолкованы как '\n'
.
Если вам не нужно это поведение (например, потому что вы пишете иличтение двоичных данных, а не текста), вам нужно использовать двоичный поток, а не текстовый поток.
Для обычных файлов это легко: просто добавьте "b"
в открытый режим при вызове fopen
.Насколько мне известно, для предопределенных потоков (stdin
/ stdout
/ stderr
) не существует переносимого решения, но в Windows есть дополнительная функция для перевода существующего потока в двоичный режим;см., например, этот ответ .
Показывает, что составляет следующий код (также можно увидеть в официальной документации Microsoft ):
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
...
_setmode( _fileno( stdout ), _O_BINARY );
В вашем коде есть несколько ошибок:
bf[0] = getchar();
if (isspace(bf[0])) continue;
if (bf[0] == EOF) goto end;
Два условия if
нарушены, потому что bf[0]
- это char
.char
недостаточно велик для хранения EOF
, который представляет собой специальное не символьное значение, возвращаемое getchar
для обозначения ошибки или конца файла.Как правило, getchar
вернет неотрицательное значение для успешного ввода и отрицательное значение (EOF
, обычно -1
) при ошибке.Присваивая это значение char
, вы усекаете EOF
и сопоставляете его с некоторым действительным значением символа.
Поведение проверки bf[0] == EOF
зависит от того, является ли char
типом со знакомна вашей платформе (это, вероятно, так).Если это так, это может привести к путанице в конце файла (например, 255, что соответствует ÿ в ISO-8859-1).Если char
без знака, это условие никогда не выполняется, поэтому вы получите бесконечный цикл.
Аналогично, isspace(bf[0])
прерывается, если char
является типом со знаком, потому что все функции is...
имеют неопределенное поведение, если их аргумент не помещается внутри unsigned char
(с одним специальным исключением: EOF
разрешено).
Исправление заключается в том, чтобы сначала сохранить результат getchar
в int
:
int c = getchar();
if (c == EOF) goto end;
if (isspace(c)) continue;
bf[0] = c;
break;