首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ungetc()能保证在scanf("...%c")之后工作吗?

ungetc()能保证在scanf("...%c")之后工作吗?
EN

Stack Overflow用户
提问于 2013-05-07 20:16:36
回答 3查看 495关注 0票数 0

我猜,ungetc()可能会在scanf("%d")之后失败,因为scanf可能会隐式调用ungetc()作为第一个非数字字符。

但是如果格式以%c结尾,就不会发生这种情况,对吧?

EN

回答 3

Stack Overflow用户

发布于 2013-05-07 20:28:19

如果阅读source code for scanf (实际上是操作scanf的内部函数),您将看到%c说明符将触发CT_CHAR切换用例的执行,这不会在标准输入上调用ungetc。所以你是对的。

这只适用于GNU libc,但我希望其他实现也有类似的行为。

票数 1
EN

Stack Overflow用户

发布于 2016-03-23 13:11:04

对于glibc,其他答案是正确的。不幸的是,从标准的角度来看,这是一个很难回答的问题。

POSIX同时指定了fscanf(3)ungetc(3),但没有描述它们之间的交互。关于前者,它是这样说的:

除非转换规范包含n转换说明符,否则应从输入中读取项目。输入项应定义为输入字节的最长序列(最大可达任何指定的最大字段宽度,可根据转换说明符以字符或字节进行测量),它是匹配序列的初始子序列。输入项后的第一个字节(如果有)将保持未读状态。

整篇文档中唯一提到的ungetc与OP的问题无关。但是,它确实确认了fscanf旨在返回通过ungetc推送回来的字符。这没有什么严重的疑问,但是ungetc从来没有定义过“读操作”是什么意思,所以在标准中有一个特定的行来指向是很有帮助的。

该标准没有具体说明“第一个字节...将保持未读状态”是什么意思。我将其解释为C库需要在未读取字符的情况下执行操作,即使任何实现都必须读取字符才能知道输入项何时结束。这反过来意味着,无论格式字符串如何,it都不应该阻止 ungetc,的使用。

(虽然这种读取可能看起来很紧张,但POSIX肯定不会说“第一个字节……应该保持未读状态,或者像ungetc()一样被推入到输入流中”,如果他们想让ungetcfscanf调用后失败,就应该这样写。)

幸运的是,ungetc的规范足够宽松,可以实际工作,允许多个字节的回推,甚至指定了在这种情况下会发生什么:

推送的字节将由该流上的后续读取以与其推送相反的顺序返回。

..。

应提供一个字节的回推。如果在同一个流上多次调用ungetc(),而没有对该流执行中间读取或文件定位操作,则操作可能会失败。

它还方便地没有指定实现必须始终提供相同数量的回推,只允许它们在第一次回推之后失败。这意味着,只要fscanf只使用一个字节,符合规范的实现就可以简单地提供两个字节的ungetc回推。

从理论上讲,我认为该标准实际上要求在调用fscanf或其姊妹函数之后,ungetc必须可用。fscanf是一个读操作,读操作应该给你留下至少一个字节的回推。实际上,这是对标准的一种非常微妙的解读,您应该预料到实现在这一点上会有所不同。

最后,作为一个实际问题,我发现这个程序可以在我的系统上成功执行,我的系统有Glibc2.21的Ubuntu变体:

代码语言:javascript
复制
#include <stdio.h>

int main(int argc, char **arv){
    FILE *file = fopen("/tmp/file.txt", "w+");
    if(file == NULL){
        perror("fopen");
        return 2;
    }
    if(fprintf(file, "123\n") == EOF){
        printf("fprintf failed.");
    }
    if(fseek(file, 0, SEEK_SET) == -1){
        perror("fseek");
        return 1;
    }
    if(ungetc((int)'1', file) == EOF){
        printf("First ungetc failed");
        return 3;
    }
    int value;
    if(fscanf(file, "%d", &value) == EOF){
        printf("fscanf failed");
        return 4;
    }
    if(ungetc((int)'2', file) == EOF){
        printf("Second ungetc failed");
        return 5;
    }
    return 0;
}

这并不能保证glibc总是做正确的事情,但它显然在这个特定的情况下做了正确的事情。

票数 1
EN

Stack Overflow用户

发布于 2014-07-03 16:25:55

当然,这并不仅仅取决于格式是否以%c结尾,因为在此之前的转换说明符可能会失败。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16418837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档