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”处出现错误。更糟糕的是,在 HP-UX 11.00 (PA-RISC) 和 HP-UX 11.23 (Itanium) 上,我在“count = 1”处出现错误 - 与 2 是安全的理论相悖。同样,AIX 6.0 在 'count = 1' 处给出错误。
因此,AIX 和 HP-UX 仅允许对一个尚未读取任何数据的输入文件进行回送字符。这是一个令人讨厌的案例;一旦从文件中读取了一些数据,它们可能会提供更多的回推容量(但是在 AIX 上添加 a getchar()
before 循环的简单测试不会改变回推容量)。
这里有一些帖子表明支持 2 个字符是有意义的scanf
。
我认为这是不对的: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
需要一个 char 本身:它可以与用户共享。
支持 2 个后推字符的实现可能这样做是为了scanf
可以ungetc
用于其后推,而不是需要第二个几乎相同的机制。这对您作为应用程序程序员意味着什么,即使调用ungetc
两次似乎有效,它可能在所有情况下都不可靠 - 例如,如果流上的最后一个操作是fscanf
并且它必须使用推回,您可能可以只有ungetc
一个字符。
在任何情况下,依靠拥有多个回退字符都是不可移植的ungetc
,所以我强烈建议不要编写需要它的代码......