* Might * unsigned char будет равно EOF?

При использовании fgetc для чтения следующего символа потока вы обычно проверяете, что конец файла не был достигнут

if ((c = fgetc (stream)) != EOF)

где c имеет тип int. Затем либо достигнут конец файла, либо условие будет терпеть неудачу, либо c будет unsigned char, преобразованным в int, который, как ожидается, будет отличаться от EOF -for EOF оказывается отрицательным. Хорошо... видимо.

Но есть небольшая проблема... Обычно тип char имеет не более 8 бит, а int должен иметь не менее 16 бит, поэтому каждый unsigned char будет представлен как int. Тем не менее, в случае, если char будет иметь 16 или 32 бита (я знаю, это никогда не бывает на практике...), нет причин, по которым нельзя было sizeof(int) == 1, так что это было бы (теоретически!) возможно, что fgetc (stream) возвращает EOF (или другое отрицательное значение), но этот конец файла не был достигнут...

Я ошибаюсь? Это что-то в стандарте C, которое предотвращает возврат fgetc EOF, если конечный файл не был достигнут? (Если да, я не мог найти его!). Или синтаксис if ((c = fgetc (stream)) != EOF) не полностью переносимый?...

EDIT: Действительно, это был дубликат вопроса # 3860943. Я не нашел этот вопрос при первом поиске. Спасибо за помощь!: -)

Ответ 1

Если вы читаете поток, который является стандартным только ASCII, нет никакого риска получить эквивалент char для EOF до реального конца файла, потому что действительные коды ASCII char доходят только до 127. Но это может произойти при чтении двоичного файла. Байт должен быть 255 (без знака), чтобы соответствовать -1 подписанному char, и ничто не мешает ему появляться в двоичном файле.

Но о вашем конкретном вопросе (если есть что-то в стандарте), а не точно... но обратите внимание, что fgetc продвигает символ как unsigned char, поэтому в любом случае он никогда не будет отрицательным. Единственный риск может быть, если вы явно или неявно сбросили возвращаемое значение на подписанный char (например, если ваша переменная c была подписана char).

ПРИМЕЧАНИЕ. Как упоминалось в комментариях @Ulfalizer, есть один редкий случай, в котором вам может потребоваться беспокоиться: if sizeof (int) == 1, и вы читаете файл, содержащий символы не-ascii, тогда вы может получить возвращаемое значение -1, которое не является реальным EOF. Обратите внимание, что среды, в которых это происходит, довольно редки (насколько мне известно, компиляторы для младших 8-разрядных микроконтроллеров, например 8051). В этом случае безопасным вариантом было бы проверить feof(), как предположил @pmg.

Ответ 2

Я думаю, вам нужно полагаться на ошибку потока.

ch = fgetc(stream);
if (ferror(stream) && (ch == EOF)) /* end of file */;

Из стандарт

Если возникает ошибка чтения, индикатор ошибки для потока установлен, а функция fgetc возвращает EOF.


Изменить для лучшей версии

ch = fgetc(stream);
if (ch == EOF) {
    if (ferror(stream)) /* error reading */;
    else if (feof(stream)) /* end of file */;
    else /* read valid character with value equal to EOF */;
}

Ответ 3

Вы спросили:

Это что-то в стандарте C, которое предотвращает возврат fgetc EOF, если конец файла не был достигнут?

Наоборот, стандарт явно позволяет возвращать EOF при возникновении ошибки.

Если возникает ошибка чтения, отображается индикатор ошибки для потока, а функция fgetc возвращает EOF.

В сносках я вижу:

Конец файла и ошибка чтения можно отличить с помощью функций feof и ferror.

Вы также спросили:

Или синтаксис if ((c = fgetc (stream)) != EOF) не полностью переносимый?

На теоретической платформе, где CHAR_BIT больше 8 и sizeof(int) == 1, это не будет правильным способом проверить, что конец файла был достигнут. Для этого вам придется прибегать к feof и ferror.

c = fgetc (stream);
if ( !feof(stream) && !ferror(stream) )
{
  // Got valid input in c.
}

Ответ 4

Я согласен с вашим чтением.

C Standard говорит (C11, 7.21.7.1 Функция fgetc p3):

Если указатель конца файла для потока установлен или поток находится в конце файла, индикатор конца файла для потока устанавливается, а функция fgetc возвращает EOF. В противном случае функция fgetc возвращает следующий символ из входного потока, на который указывает поток. Если возникает ошибка чтения, отображается индикатор ошибки для потока и функция fgetc возвращает EOF.

В стандарте нет (при условии UCHAR_MAX > INT_MAX), который запрещает fgetc в размещенной реализации возвращать значение, равное EOF, которое не является ни концом файла, ни индикатором условия ошибки.