ungetc
只保证接受一个字节的推回。另一方面,我在 Windows 和 Linux 上测试了它,它似乎可以使用两个字节。
有没有任何平台(例如任何当前的 Unix 系统)实际上只需要一个字节?
C99标准(以及之前的C89标准)明确表示:
保证一个字符的推回。如果
函数被调用过多 同一流上的时间,无需干预读取或文件定位操作 流,操作可能会失败。ungetc
因此,为了便于移植,您不应假设有多个推回字符。
话虽如此,在 MacOS X 10.7.2 (Lion) 和 RHEL 5 (Linux, x86/64) 上,我尝试过:
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 4096; i++)
{
int c = i % 16 + 64;
if (ungetc(c, stdin) != c)
{
fprintf(stderr, "Error at count = %d\n", i);
return(1);
}
}
printf("No error up to count = %d\n", i-1);
return(0);
}
我在两个平台上都没有遇到错误。相比之下,在 Solaris 10 (SPARC) 上,我在“count = 4”处收到错误,在 Solaris 11.3 上也是如此。更糟糕的是,在 HP-UX 11.00 (PA-RISC)、HP-UX 11.23 (Itanium) 和 HP-UX 11.31 (Itanium) 上,我在“count = 1”处收到错误 - 违背了 2 是安全的理论。同样,AIX 6.0(和 7.2)在“count = 1”处给出错误。
因此,AIX 和 HP-UX 只允许在尚未读取任何数据的输入文件上推回一个字符。这是一个令人厌恶的案例;一旦从文件中读取了一些数据,它们可能会提供更多的推回能力(但在 AIX 上进行的简单测试在循环之前添加
getchar()
并没有改变推回能力)。
这里有一些帖子建议为了
scanf
支持 2 个字符是有意义的。
我认为这是不对的:
scanf
只需要一个,这确实是限制的原因。最初的实现(早在 70 年代中期)支持 100,并且手册中有一个注释:将来我们可能决定仅支持 1,因为这就是 scanf 所需要的。 请参阅原始手册的第 3 页(也许不是原创,但相当旧了。)
要更生动地看到 scanf 只需要 1 个字符,请将此代码视为
%u
的 scanf
功能。
int c;
while isspace(c=getc()) {} // skip white space
unsigned num = 0;
while isdigit(c)
num = num*10 + c-'0',
c = getc();
ungetc(c);
这里只需要调用一次
ungetc()
。 scanf
没有理由需要一个单独的字符:它可以与用户共享。
支持 2 个推回字符的实现可能会这样做,以便
scanf
可以使用 ungetc
进行推回,而不需要第二个几乎相同的机制。对于应用程序程序员来说,这意味着即使调用 ungetc
两次似乎有效,但它可能并不在所有情况下都可靠 - 例如,如果流上的最后一个操作是 fscanf
并且它必须使用推回,您可能只能ungetc
一个字符。
无论如何,依赖于具有多个
ungetc
推回字符是不可移植的,所以我强烈建议不要编写需要它的代码......