Почему 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).

Другие вопросы по тегам