【问题标题】:fmt.Scanf does not consume all the characters through the end of the stringfmt.Scanf 不会消耗到字符串末尾的所有字符
【发布时间】:2021-02-28 19:05:27
【问题描述】:
package main
import "fmt"

func main(){
    var i int
    fmt.Print("input integer: ")
    fmt.Scanf("%d", &i)

}

当我从终端运行这个小程序并给出输入时

input integer: 3.ls

它还执行ls 命令 或者当我提供输入时

input integer: 665.cd someDir

它执行cd someDir。 这是 Go 中 Scanf 的正常行为吗?这在 C 中不会发生。 有人可以解释发生了什么。

【问题讨论】:

  • 不,这不是标准库中的错误。这绝不是标准库中的错误。

标签: go scanf


【解决方案1】:

不是答案,只是对@icza 所写内容的扩展,但太大而无法放入评论。

我也会尝试更多地解释为什么会这样

在 C 中不会发生

效果发生了。

您很可能使用过scanf(3),其同类函数不是对文件描述符(如系统调用包装器,如read(2)write(2))进行操作,而是对所谓的C标准库提供的“流”;这些设施被称为"stdio"

这些流提供默认缓冲,stdin 通常默认为行缓冲。

考虑以下程序:

#include <stdio.h>

int main()
{
    int rc, i;

    printf("input integer: ");

    rc = scanf("%d", &i);
    if (rc != 1) {
        perror("scan failed");
        return 1;
    }

    return 0;
}

如果我们构建它

$ gcc -o scanf -W -Wall -Werror scanf.c

然后“按原样”运行,我们观察到程序已经消耗了那些额外的.ls 字符:

$ ./scanf
input integer: 3.ls
$

现在让我们看看当我们修改缓冲的想法以默认使用链接到我们的程序的libc 时会发生什么。我们将为此使用stdbuf

$ stdbuf -i 0 ./scanf
input integer: 3.ls
scanf scanf.c
$

这就是@icza 的建议有效的原因:在 Go 中,构成os 包的变量用于保存打开到标准流的文件对象,因为它们的类型为*os.File,所以它们没有缓冲,而且它们是非常薄的包装器操作系统返回的文件描述符。

如果你需要缓冲,你应该在它所属的地方显式使用它(并且要小心:不要在缓冲包装器及其底层数据源/接收器上混合读取/写入 - 至少除非你绝对确定你的'正在做)。

【讨论】:

    【解决方案2】:

    您的 fmt.Scanf("%d", &amp;i) 调用仅从输入中解析一个整数,它不会在行尾之前使用输入。

    如果输入3.ls,则3被解析为十进制数,.被消耗,将停止扫描。您的应用程序到此结束,因此其余部分(ls 和换行符)将由您的 shell 执行。

    使用bufio.Scanner 读取,例如:

    fmt.Print("input string: ")
    scanner := bufio.NewScanner(os.Stdin)
    if !scanner.Scan() {
        return // no input
    }
    var i int
    fmt.Sscanf(scanner.Text(), "%d", &i)
    fmt.Println("Entered:", i)
    

    查看相关:Tell me what's wrong with this code GOLANG

    【讨论】:

    • 想要添加一个评论来扩展那个缓冲的东西,但最终对于评论来说太大了。如果您发现该信息相关,请随时将其包含在您的答案中,我将删除我的;-)
    • @kostix 我认为作为您单独的答案很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 2023-03-29
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    相关资源
    最近更新 更多