fmt.Scanf 不消耗字符串末尾的所有字符
fmt.Scanf does not consume all the characters through the end of the string
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.This 中 Scanf 的这种正常行为在 C 中不会发生吗?
谁能解释一下这是怎么回事。
您的 fmt.Scanf("%d", &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)
查看相关:
不是答案,只是对@icza 所写内容的扩展,但太大而无法放入评论。
我也会尝试阐明原因
does not happen in C
效果发生。
很可能你用过scanf(3)
, and the functions of its ilk operate not on file descriptors (like syscall wrappers such as read(2)
and write(2)
) but rather on so-called "streams" provided by the C standard library; these facilities are referred to as "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
类型,并且这些是 OS.
返回的文件描述符的非常薄的包装器
如果你需要缓冲,你应该明确地在它所属的地方使用它(并且要小心:不要在缓冲包装器和它的底层数据上混合 reads/writes - 至少除非你绝对确定你在做什么)。
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.This 中 Scanf 的这种正常行为在 C 中不会发生吗?
谁能解释一下这是怎么回事。
您的 fmt.Scanf("%d", &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)
查看相关:
不是答案,只是对@icza 所写内容的扩展,但太大而无法放入评论。
我也会尝试阐明原因
does not happen in C
效果发生。
很可能你用过scanf(3)
, and the functions of its ilk operate not on file descriptors (like syscall wrappers such as read(2)
and write(2)
) but rather on so-called "streams" provided by the C standard library; these facilities are referred to as "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
类型,并且这些是 OS.
如果你需要缓冲,你应该明确地在它所属的地方使用它(并且要小心:不要在缓冲包装器和它的底层数据上混合 reads/writes - 至少除非你绝对确定你在做什么)。