[英]Why I still need to press 'Enter" in order to let input be read and output even in non-canonical mode?
I was testing this code from the GNU libc manual: 我正在从GNU libc手册中测试以下代码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
/* Use this variable to remember original terminal attributes. */
struct termios saved_attributes;
void
reset_input_mode (void)
{
tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
}
void
set_input_mode (void)
{
struct termios tattr;
char *name;
/* Make sure stdin is a terminal. */
if (!isatty (STDIN_FILENO))
{
fprintf (stderr, "Not a terminal.\n");
exit (EXIT_FAILURE);
}
/* Save the terminal attributes so we can restore them later. */
tcgetattr (STDIN_FILENO, &saved_attributes);
atexit (reset_input_mode);
/* Set the funny terminal modes. */
tcgetattr (STDIN_FILENO, &tattr);
tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0;
tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
}
int
main (void)
{
char c;
set_input_mode ();
while (1)
{
read (STDIN_FILENO, &c, 1);
if (c == '\004') /* C-d */
break;
else
putchar (c);
}
return EXIT_SUCCESS;
}
Even though the terminal was set to be in non-canonical mode, I still need to press enter for input to be received. 即使终端设置为非规范模式,我仍然需要按Enter才能接收输入。
However, if I change: putchar(c)
to write(STDOUT_FILENO, &c, sizeof(char))
, it works properly as I thought. 但是,如果我更改:
putchar(c)
write(STDOUT_FILENO, &c, sizeof(char))
,它可以按照我的想法正常工作。
You are being trumped by user buffering! 您正在被用户缓冲所压倒!
putchar(3)
is part of libc I/O API, while write(2)
is a system call -- well, not quite a system call, but for simplicity's sake, let's consider it is for now. putchar(3)
是libc I / O API的一部分,而write(2)
是系统调用-嗯,这不完全是系统调用,但是为了简单起见,现在考虑一下。
There are three types of buffering in libc: unbuffered, block buffered, and line buffered. libc中有三种缓冲类型:未缓冲,块缓冲和行缓冲。 If a stream is unbuffered, data goes to the underlying file (or terminal) as soon as it is written;
如果流没有缓冲,则数据在写入后立即进入底层文件(或终端)。 if it's block buffered, data is saved in the memory block until it fills up and then it's written all at once;
如果是块缓冲的,则将数据保存在内存块中,直到数据填满,然后立即将其全部写入。 however, if it's line buffered, data is transmitted to the file (or terminal) when a newline character is found.
但是,如果是行缓冲的,则当找到换行符时,数据将传输到文件(或终端)。
If a stream is connected to a terminal, as normally is the case of standard output, it's line buffered. 如果将流连接到终端(通常是标准输出的情况),则会对其进行行缓冲。 So, this is your case: when you press enter, the newline character
\\n
causes the (line) buffer to be written to standard output. 因此,这是您的情况:当您按Enter键时,换行符
\\n
导致(行)缓冲区被写入标准输出。 However, when you call write(2)
, libc user buffering is bypassed and data is written to the corresponding file descriptor (STDOUT_FILENO). 但是,当您调用
write(2)
,将绕过libc 用户缓冲 ,并将数据写入相应的文件描述符 (STDOUT_FILENO)。
So, as I said earlier, write(2)
is a system call; 因此,正如我之前所说,
write(2)
是一个系统调用; but in truth, when you call write
, you are calling a library wrapper to the system call, which handles the strict protocol the system call follows (eg, where it expects arguments, etc). 但实际上,当您调用
write
,您是在对系统调用进行库包装,该系统处理了系统调用遵循的严格协议(例如,期望参数的位置等)。
By the way, everything I said here can be found in the man pages for putchar(3)
, write(2)
, setbuf(3)
. 顺便说一句,我在这里所说的所有内容都可以在
putchar(3)
, write(2)
, setbuf(3)
的手册页中找到。 The numbers in parentheses refer to the section in the manual: 2
is for system calls, 3
is for library functions ( man man
should give you a list of sections and their topic). 括号中的数字指的是手册中的部分 :
2
用于系统调用, 3
用于库函数( man man
应该给您列出节及其主题)。
Hope it helps. 希望能帮助到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.