- В C
EOF
- это «небольшое отрицательное число».
- В C тип
char
может быть без знака, что означает, что он не может представлять отрицательные значения.
- Для типов без знака, когда вы пытаетесь присвоить им отрицательное значение, они преобразуются в значение без знака. Если
MAX
является максимальным значением, которое может содержать тип без знака, то присвоение -n
такому типу эквивалентно присвоению ему MAX - (n % MAX) + 1
. Итак, чтобы ответить на ваш конкретный вопрос о прогнозировании, «да, вы можете». Например, допустим, что char
не имеет знака и может содержать значения от 0
до 255
включительно. Тогда присвоение -1
для символа эквивалентно присвоению 255 - 1 + 1 = 255
для него.
Учитывая вышеизложенное, для возможности хранить EOF
в c
, c
не может быть char
типа. Таким образом, мы используем int
, потому что он может хранить «маленькие отрицательные значения». В частности, в C int
гарантированно хранятся значения в диапазоне -32767
и +32767
. Вот почему getchar()
возвращает int
.
Кроме того, означает ли это, что тип данных "char" можно использовать только тогда, когда мы просто присваиваем значение переменной вручную, например char c = 'a', когда мы точно знаем, что у нас будет только 256 возможных символов ASCII?
Если вы присваиваете значения напрямую, то стандарт C гарантирует, что выражения типа 'a'
поместятся в char
. Обратите внимание, что в C * 'a'
имеет тип int
, а не char, но это нормально делать char c = 'a'
, потому что 'a'
может соответствовать типу char
.
По поводу вашего вопроса о том, какой тип должна содержать переменная, ответ таков: используйте любой тип, который имеет смысл. Например, если вы считаете или смотрите на длину строки, числа могут быть только больше или равны нулю. В таких случаях вы должны использовать беззнаковый тип. size_t
такой тип.
Обратите внимание, что иногда сложно определить тип данных, и даже "профи" могут ошибаться. Формат gzip
, например, хранит размер несжатых данных в последних 4 байтах файла. Это касается больших файлов размером более 4 ГБ, которые в наши дни довольно распространены.
Вы должны быть осторожны с вашей терминологией. В C char c = 'a'
присваивает целочисленное значение, соответствующее 'a'
- c
, но оно не обязательно должно быть ASCII. Это зависит от того, какую кодировку вы используете.
О части "modulo" и 256 значениях типа char
: если у вас есть n
двоичных битов в типе данных, каждый бит может кодировать 2 значения: 0 и 1. Итак, у вас есть 2*2*2...*2
(n
раз) доступные значения, или 2 n . Для типов без знака любое переполнение четко определено, как если бы вы поделили число на (максимально возможное значение + 1) и взяли остаток. Например, скажем, unsigned char
может хранить значения 0..255
(всего 256 значений). Затем, присваивая 257
unsigned char
, мы в основном разделим его на 256, возьмем остаток (1) и присвоим это значение переменной. Это отношение справедливо только для неподписанных типов. См. мой ответ на другой вопрос для получения дополнительной информации.
Наконец, вы можете использовать массивы char
для чтения данных из файла в C, даже если вы в конечном итоге нажмете EOF
, потому что C предоставляет другие способы обнаружения EOF
без необходимости читать его в переменной в явном виде, но вы узнаете об этом позже, когда прочтете о массивах и указателях (см. fgets()
, если вам интересен один пример).