ungetc:pushback的字节数

rwa*_*ace 4 c unix stdio ungetc

ungetc只能保证一个字节的后推.另一方面,我在Windows和Linux上测试过,它似乎可以使用两个字节.

是否有任何平台(例如任何当前的Unix系统)实际上只需要一个字节?

Jon*_*ler 6

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);
}
Run Code Online (Sandbox Code Playgroud)

我在任何一个平台上都没有错误.相比之下,在Solaris 10(SPARC)上,我在'count = 4'时收到错误.更糟糕的是,在HP-UX 11.00(PA-RISC)和HP-UX 11.23(Itanium)上,我在'count = 1'时遇到了错误 - 认为2是安全的.同样,AIX 6.0在'count = 1'时给出了错误.

摘要

  • Linux:大(4 KiB)
  • MaxOS X:大(4 KiB)
  • Solaris:4
  • HP-UX:1
  • AIX:1

因此,AIX和HP-UX仅允许在没有读取任何数据的输入文件上使用一个回退字符.这是一个令人讨厌的案件; 一旦从文件中读取了一些数据,它们可能会提供更多的回推容量(但是在AIX getchar()之前添加一个简单的测试并没有改变回送容量).

  • 请注意,超过推回限制会导致失败而不是 UB - 对于熟悉 C 处理非可移植代码的常用方式的程序员来说,这是一个惊喜。因此,原则上,如果第二个字符返回失败,您总是可以*尝试* 推回 2 个字符并退回到更昂贵的解决方案(如`fseek`,如果您的文件可查找)。 (2认同)

R..*_*R.. 5

支持 2 个推回字符的实现可能这样做是为了scanf可以用于ungetc其推回,而不是需要第二个几乎相同的机制。对于应用程序程序员来说,这意味着即使调用ungetc两次似乎可行,但它可能并不在所有情况下都是可靠的——例如,如果流上的最后一个操作是fscanf并且它必须使用推回,那么您可能可以只有ungetc一个字符。

无论如何,依赖于具有多个ungetc推回字符是不可移植的,因此我强烈建议不要编写需要它的代码......


Mar*_* VY 5

这里有一些帖子建议为了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);
Run Code Online (Sandbox Code Playgroud)

ungetc()这里只需要一次调用。没有理由scanf需要一个单独的字符:它可以与用户共享。