Почему «unsigned int» НЕ отличается от EOF - может ли он хранить отрицательные значения? - PullRequest
3 голосов
/ 26 марта 2019

Я пытаюсь прочитать файл растрового изображения, побайтово, и у меня есть цикл, который работает до достижения EOF.Для этого у меня есть переменная, объявленная как unsigned int, которая хранит каждый байт.Цикл останавливается, когда эта переменная равна EOF.

Интересный момент: если я объявлю свою переменную как unsigned int, она будет работать.Однако, если я объявлю свою переменную как unsigned short int, цикл будет выполняться вечно, потому что он никогда не найдет EOF.

#include <stdio.h>

int main()
{
    FILE *file;
    unsigned int currentByte;

    file = fopen("/home/stanley/Desktop/x.bmp", "rb");

    while ((currentByte = fgetc(file)) != EOF) {
        printf("%d \n", currentByte);
    }

    fclose(file);
    return 0;
}

Код выше - это код, который я пишу.Если размер файла составляет 90B, на экране выводится 90 байт.

Однако по какой-то причине, когда я изменяю его на unsigned short int currentByte, цикл продолжает работать вечно.Как будто currentByte никогда не было равно EOF.

Я где-то читал, что EOF содержит отрицательное значение (-1).Но если EOF отрицательно, почему он работает, когда я использую только unsigned int, и почему он вызывает ошибку, когда я использую unsigned short int?Теоретически, не должна ли проблема быть связана с самим unsigned, а не с short?Это без знака, который не может хранить отрицательные значения.

Извините, если это очень глупый вопрос.Я пытаюсь лучше понять, как работают биты и байты, и некоторые концепции еще могут показаться мне странными.

Я компилирую его в следующей среде:

  • ОС:Ubuntu 18.04 x64
  • GCC: gcc (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0

Заранее спасибо.:)

Ответы [ 3 ]

3 голосов
/ 26 марта 2019

Если размер int больше размера short, то вы столкнетесь с этой проблемой.

Предположим, что EOF имеет тип int и содержит значение -1.Для примера давайте также предположим, что int является 32-битным значением, а short является 16-битным значением.

В этом случае, если fgetc возвращает EOF,он будет иметь значение 0xFFFFFFFF, когда принимается за unsigned int.При сравнении с EOF (тип int) целое число со знаком -1 будет преобразовано в значение без знака 0xFFFFFFFF.Эти два значения равны, поэтому сравнение работает, как и ожидалось.

Однако, EOF, возвращаемый fgetc, принятый как unsigned short, будет иметь значение 0xFFFF.Поскольку размер unsigned short меньше размера int, при сравнении этого значения с EOF unsigned short 0xFFFF будет преобразовано в int со значением 0x0000FFFF (для ясности показаны дополнительные цифры).Поскольку -1 не равно 0xFFFF для 32-разрядного значения, это сравнение всегда не равно и цикл не остановится.

Тот факт, что fgetc возвращает int, указывает, что вы должны сохранитьэто как этот тип, так как иначе вы отбросите некоторую информацию или вызовете путаницу при сравнении.

2 голосов
/ 26 марта 2019

При преобразовании целого числа со знаком в целое число без знака (что происходит, когда переменной целого числа без знака присваивается EOF), результат преобразуется в целое число без знака путем добавления UINT_MAX + 1. Поэтому, если EOF равно -1, это значение становится UINT_MAX.

И UINT_MAX могут корректно вписываться только в unsigned int, а не unsigned short. И результат этого конкретного преобразования определяется реализацией, поэтому поведение программы будет зависеть от него.

Обратите внимание, что функция fgetc возвращает int, поэтому вы должны использовать переменную int для хранения ее значения.

2 голосов
/ 26 марта 2019

Вы должны использовать тип int, чтобы соответствовать тому, что возвращает fgetc, а не unsigned int. Причина, по которой условие остановки цикла работает с unsigned int, заключается не в том, что значение всегда отрицательно, а в том, что когда оператор != используется с операндами unsigned и signed одного ранга, оба получают повышение до unsigned до сравнения. Присвоение результата EOF от fgetc до currentByte и повышение от EOF до unsigned дают одинаковый результат, и, таким образом, они сравниваются равными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...