为什么 ungetc 在某些字符上会失败?

Why does ungetc fail on some characters?

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 系统上测试了相同的代码,它的行为与预期的一样。是否存在某种未定义的行为?

基于以下假设:

  • 您所处的系统对纯字符进行了签名。
  • '\xFF' 在您的系统上是 -1(超出范围的字符常量的值是实现定义的,见下文)。
  • EOF 在您的系统上是 -1

调用 ungetc('\xFF', stdin);ungetc(EOF, stdin); 相同,其行为由 C11 7.21.7.10/4:

涵盖

If the value of c equals that of the macro EOF, the operation fails and the input stream is unchanged.


ungetc的输入范围与getchar的输出范围相同,即EOF是负数,或者表示一个字符的非负值(带负数通过转换为 unsigned char 来表示的字符)。我猜你打算 ungetc(255, stdin);.


关于'\xFF'的取值,见C11 6.4.4.4/10:

The value of an integer character constant [...] containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined.

此外,执行字符集的值是实现定义的 (C11 5.2.1/1)。您可以查看编译器文档来确定,但编译器行为表明 255 不在执行字符集中;事实上,我测试的 gcc 版本的行为表明它采用 char 的范围作为执行字符集(而不是 unsigned char 的范围)。