GetChar()即使在随后的呼叫后仍会返回EOF,但读取()系统呼叫似乎是“清晰的” stdin。背后的原因是什么?
char buff[1];
int main() {
int c;
c = getchar();
printf("%d\n", c); //output -1
c = getchar();
printf("%d\n", c); // output -1
int res;
//here I get a prompt for input. What happened to EOF ?
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
return 0;
}
代码中使用注释的行显示的结果输出是简单地键入 ctrl-d (MacOS上的eof
)。
我对getchar()
的行为有些困惑,尤其是与读取
相比。
是否应该读取
内的系统调用
循环也返回eof
?他们为什么提示用户?是否发生过某种stdin
明确发生了?考虑到
getchar()
使用读取
在引擎盖下的系统调用,他们的行为如何有所不同?stdin
不应该是“唯一”,而eof
共享条件?如何在以下代码中获得两个
读取
系统调用返回eof
当给出 ctrl-d 输入时?
int res;
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
我试图在所有这些背后找到逻辑。希望某人可以清楚地表明eof
真正的行为方式。
PS我正在使用Mac OS机器
char buff[1];
int main() {
int c;
c = getchar();
printf("%d\n", c); //output -1
c = getchar();
printf("%d\n", c); // output -1
int res;
//here I get a prompt for input. What happened to EOF ?
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
return 0;
}
The resulting output showed with commented lines in the code is the result of simply typing Ctrl-D (EOF
on macOS).
I'm a bit confused about the behaviour of getchar()
, especially when compared to read
.
Shouldn't the
read
system calls inside thewhile
loop also returnEOF
? Why do they prompt the user? Has some sort ofstdin
clear occurred?Considering that
getchar()
uses theread
system call under the hood how come they behave differently? Shouldn't thestdin
be "unique" and theEOF
condition shared?How come in the following code the two
read
system calls return bothEOF
when a Ctrl-D input is given?
int res;
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
while ((res = read(0, buff, 1)) > 0) {
printf("Hello\n");
}
I'm trying to find a logic behind all this. Hope that someone could make it clear what EOF
really is a how it really behaves.
P.S I'm using a Mac OS machine
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一旦设置了
stdin
,getchar()
不尝试阅读。清除文件终止指示器(例如
clearerr()
或其他)重新读取。read()
仍尝试每次读取。注意:通过
文件 *
读取,例如stdin
,如果设置了文件终止指示器,则不会尝试阅读。但是,即使设置了错误指示器,仍会发生读取尝试。Once the end-of-file indicator is set for
stdin
,getchar()
does not attempt to read.Clear the end-of-file indicator (e.g.
clearerr()
or others) to re-try reading.read()
still tries to read each time.Note: Reading via a
FILE *
, likestdin
, does not attempt to read if the end-of-file indicator is set. Yet even if the error indicator is set, a read attempt still occurs.MACOS是BSD Unix系统的衍生产品。它的STDIO实现不是来自GNU软件,因此是不同的实现。在EOF上,发出
读取(2)
系统调用并接收0作为读取的字符数时,文件描述符被标记为错误2)再次直至重置错误条件,并产生您观察到的行为。在发出下一个getchar(3)
调用之前,请使用clearerr(stream);
在文件 *
描述符上使用,一切都很好。您也可以使用GLIB来执行此操作,然后,您的程序将在STDIO的任何一个实施中运行(GLIB vs. BSD)eof
只是一个常数(通常为-1),它与任何可能的char> char
值由getchar(3)
(<)代码> getchar()在0..255中返回int
,而不是为此目的返回char,以扩展范围OS可能具有一个可能的字符,以代表EOF条件,但EOF不是一个char)文件条件的结束是由getchar函数家族(getchar,fgetC等)表示的,因为文件的结束是由read> read(2)
发出的。返回值为0(返回字符的数量为零),该值不会映射为某些字符。...因此,可能的字符数被扩展到整数和新值eof
定义为在到达文件状态结束时返回。这与具有CTRL-D字符(ASCII EOT或CNTRL-D,十进制值4)的文件兼容,并且不表示文件状态的结尾(当您从文件中读取ASCII EOT时4)另一侧的UNIX TTY实现允许在线输入模式使用特殊字符(CTRL-D,ASCII EOT/传输末端,小数值4),以指示流和末端到驱动程序... 。没有读取的内容,您将获得文件的末尾),因此请认为cntrl-d仅在UNIX TTY驱动程序中仅是特殊,并且仅当它以规范模式(行输入模式)工作时。因此,最后,只有两种方法可以在行模式下将数据输入程序:
'\ n '
字符),ASCII LF字符输入到程序读取(2)
呼叫从缓冲区有效地读取零字符。为了在每种情况下统一,
读取(2)
系统调用通常会阻止内核直到一个或多个字符可用。...该程序。这应该是您的文件指示。许多程序读取不完整的缓冲区(小于您作为参数传递的字符数),然后在文件的真实末尾发出信号之前,因此,几乎每个程序都会读取另一个程序以检查是否是不完整的读数,或者确实是结束文件指示。最后,如果我想将CNTRL-D字符作为文件输入CNTRL-D字符。...TTY实现中还有另一个特殊字符,可以使您能够逃脱此前面的特殊字符上的特殊行为。在当今的系统中,该字符默认是CTRL-V,因此,如果要输入特殊字符(甚至是?ctrl-v),则必须使用CTRL-V之前使用它,使得将CTRL-D输入到文件中才能必须输入CTRL-V + CTRL-D。
MacOs is a derivative of BSD unix systems. Its stdio implementation does not come from GNU software and so it is a different implementation. On EOF, the file descriptor is marked as erroneous when issuing a
read(2)
system call and receiving 0 as the number of characters returned by read, and so, it doesn'tread(2)
it again until the error condition is reset, and this produces the behaviour you observe. Useclearerr(stream);
on theFILE *
descriptor before issuing the nextgetchar(3)
call, and everything will be fine. You can do that with glib also, and then, your program will run the same in either implementation of stdio (glib vs. bsd)EOF
is simply a constant (normally it's valued as -1) that is different to any possiblechar
value returned bygetchar(3)
(getchar()
returns anint
in the interval 0..255, and not a char for this purpose, to extend the range os possible characters with one more to represent the EOF condition, but EOF is not a char) The end of file condition is so indicated by the getchar family of functions (getchar, fgetc, etc) as the end of file condition is signalled by aread(2)
return value of 0 (the number of returned characters is zero) which doesn't map as some character.... for that reason, the number of possible chars is extended to an integer and a new valueEOF
is defined to be returned when the end of file condition is reached. This is compatible with files that have Ctrl-D characters (ASCII EOT or Cntrl-D, decimal value 4) and not representing an END OF FILE condition (when you read an ASCII EOT from a file it appears as a normal character of decimal value 4)The unix tty implementation, on the other side, allows on line input mode to use a special character (Ctrl-D, ASCII EOT/END OF TRANSMISSION, decimal value 4) to indicate and end of stream to the driver.... this is a special character, like ASCII CR or ASCII DEL (that produce line editing in input before feeding it to the program) in that case the terminal just prepares all the input characters and allows the application to read them (if there's none, none is read, and you got the end of file) So think that the Cntrl-D is only special in the unix tty driver and only when it is working in canonical mode (line input mode). So, finally, there are only two ways to input data to the program in line mode:
'\n'
character) and the ASCII LF character is input to the programread(2)
call reads effectively zero characters from the buffer.To unify, in every scenario, the
read(2)
system call normally blocks into the kernel until one or more characters are available.... only at end of file, it unblocks and returns zero characters to the program. THIS SHOULD BE YOUR END OF FILE INDICATION. Many programs read an incomplete buffer (less than the number of characters you passed as parameter) before a true END OF FILE is signalled, and so, almost every program does another read to check if that was an incomplete read or indeed it was an end of file indication.Finally, what if I want to input a Cntrl-D character as itself to a file.... there's another special character in the tty implementation that allows you to escape the special behaviour on the special character this one precedes. In today systems, that character is by default Ctrl-V, so if you want to enter a special character (even ?Ctrl-V) you have to precede it with Ctrl-V, making entering Ctrl-D into the file to have to input Ctrl-V + Ctrl-D.