Почему ungetc не работает на некоторых персонажах?
ungetc()
Кажется, не на некоторых персонажей. Вот простая тестовая программа:
#include <stdio.h>
int main(void) {
int c;
printf("Type a letter and the enter key: ");
#define TRACE(x) printf("%s -> %d\n", #x, x)
TRACE(c = getc(stdin));
TRACE(ungetc(c, stdin));
TRACE(getc(stdin));
TRACE(ungetc('\xFE', stdin));
TRACE(getc(stdin));
TRACE(ungetc('\xFF', stdin));
TRACE(getc(stdin));
return 0;
}
Я запускаю его в системе Unix и набираю a
Введите в командной строке
Выход:
Type a letter and the enter key: a
c = getc(stdin) -> 97
ungetc(c, stdin) -> 97
getc(stdin) -> 97
ungetc('\xFE', stdin) -> 254
getc(stdin) -> 254
ungetc('\xFF', stdin) -> -1
getc(stdin) -> 10
Я ожидал этого:
Type a letter and the enter key: a
c = getc(stdin) -> 97
ungetc(c, stdin) -> 97
getc(stdin) -> 97
ungetc('\xFE', stdin) -> 254
getc(stdin) -> 254
ungetc('\xFF', stdin) -> 255
getc(stdin) -> 255
Почему вызывает ungetc()
терпеть неудачу?
РЕДАКТИРОВАТЬ: что еще хуже, я протестировал один и тот же код на другой системе Unix, и он ведет себя так, как ожидалось. Есть ли какое-то неопределенное поведение?
1 ответ
Работаем на следующих предположениях:
- Вы находитесь в системе, где подписан простой символ.
'\xFF'
является-1
в вашей системе (значение символьных констант вне диапазона определяется реализацией, см. ниже).EOF
является-1
в вашей системе.
Вызов ungetc('\xFF', stdin);
такой же как ungetc(EOF, stdin);
чье поведение подпадает под C11 7.21.7.10/4:
Если значение
c
равно что из макросаEOF
операция завершается неудачно и входной поток не изменяется.
Диапазон ввода для ungetc
такой же, как выходной диапазон getchar
т.е. EOF
который является отрицательным или неотрицательным значением, представляющим символ (с отрицательными символами, представленными их преобразованием в unsigned char
). Я полагаю, вы шли на ungetc(255, stdin);
,
Что касается стоимости '\xFF'
см. C11 6.4.4.4/10:
Значение целочисленной символьной константы [...], содержащей символ или escape-последовательность, которая не отображается на однобайтовый символ выполнения, определяется реализацией.
Кроме того, значения набора символов выполнения определяются реализацией (C11 5.2.1/1). Вы можете проверить документацию компилятора, чтобы убедиться, но поведение компилятора предполагает, что 255
отсутствует в наборе символов выполнения; и на самом деле поведение версии GCC, которую я протестировал, предполагает, что он принимает диапазон char
в качестве набора символов выполнения (не диапазон unsigned char
).