0

我正在玩以下两个代码片段

// Snippet1 in C
#include <stdio.h>

int main(){
    FILE * fp = fopen("/dev/tty", "r");

    int c = getc(fp);
    printf("%d", c);
}
// Snippet2 in Rust
use std::io::Read;
use std::fs;

fn main() {
    let mut f: fs::File = fs::File::open("/dev/tty").unwrap();
    let mut buf: [u8;1] = [0];

    f.read_exact(&mut buf).unwrap();
    print!("byte: {}", buf[0]);
}

上面的代码要做的是从用户键盘读取一个字节,然后将其打印到标准输出。令人困惑的是两个片段有不同的行为:

➜  playground gcc main.c -o main
➜  playground ./main
a                                  # input a and press Enter
97%
➜  playground cargo run -q
a                                  # input a and press Enter
byte: 97%                                                                ➜  playground
➜  playground

很抱歉上面代码的格式,我不知道如何将提示放在新行的开头:(

请注意, Rust代码执行后有两个shell提示?➜ playground

我猜它Enter被发送到输入缓冲区,就好像我在执行后按下它一样。

如果我知道缓冲区中实际发生了什么,我会找出这种区别的原因,所以我想知道那里发生了什么?

顺便说一句,我的环境:

➜  playground rustc --version
rustc 1.57.0 (f1edd0429 2021-11-29)
➜  playground gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

如果我的问题不被允许,请随时要求我删除它:) 提前致谢:)

4

1 回答 1

2

请注意,在 C 中,FILE*相应的函数是缓冲的,因此 C 程序读取键和换行符并将它们放入缓冲区中,而您的 Rust 代码不使用缓冲。因此,当您的 Rust 程序完成时,换行符仍在 TTY 的内核缓冲区中,因此您的 shell 可以看到换行符,而换行符已被您的 C 程序从内核缓冲区中删除。

使用这个无缓冲的 C 代码,你应该得到与你的 Rust 程序相同的行为:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd = open ("/dev/tty", O_RDONLY);

    char c;
    read (fd, &c, 1);
    printf("%d", c);
}

或与您的 C 程序具有此缓冲 Rust 代码的相同行为:

use std::io::{ BufReader, Read };
use std::fs;

fn main() {
    let mut f = BufReader::new (fs::File::open("/dev/tty").unwrap());
    let mut buf: [u8;1] = [0];

    f.read_exact(&mut buf).unwrap();
    print!("byte: {}", buf[0]);
}
于 2022-01-18T10:51:57.173 回答