为什么 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
的范围)。
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 macroEOF
, 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
的范围)。