this post was submitted on 27 Jun 2023
6 points (100.0% liked)
C Programming Language
993 readers
1 users here now
Welcome to the C community!
C is quirky, flawed, and an enormous success.
... When I read commentary about suggestions for where C should go, I often think back and give thanks that it wasn't developed under the advice of a worldwide crowd.
... The only way to learn a new programming language is by writing programs in it.
- irc: #c
๐ https://en.cppreference.com/w/c
founded 1 year ago
MODERATORS
you are viewing a single comment's thread
view the rest of the comments
view the rest of the comments
If you're on Linux then I'm pretty sure the confusing behavior you're seeing is due to the line buffering the kernel does by default.
Ctrl+D
does not actually mean "send EOF", and it's not the "EOF character", rather it means "complete the current or next stdin read() request immediately". That's a very different thing, and sometimes it means EOF and other times it does not.In practice what this means is that, if there is no data waiting to be sent on stdin then
read()
returns zero, andread()
returning zero is howgetchar()
knows an EOF happened. The flow looks like this:getchar()
.getchar()
callsread()
on stdin and your program blocks waiting for input.Ctrl+D
on the tty, having not typed anything else.read()
call and returns zero bytes read.getchar()
sees that it got no bytes fromread()
and returnsEOF
.However, in practice it doesn't work that cleanly because the tty is normally operating in "cooked" mode, where the kernel sends input to your program line by line, allowing the user to edit a single line before sending it. The way this works is by buffering the
stdin
contents and sending it when the user hits enter. Going back toCtrl-D
, you can see how this screws things up, leading to the behavior you see:getchar()
.getchar()
callsread()
on stdin and your program blocks waiting for input.stdin
buffer and is not send to your program yet.Ctrl+D
on the tty.read()
call and starts returning the currently bufferedstdin
input, without waiting for an enter press.getchar()
sees that it got a byte fromread()
and thus returns it.getchar()
has seen all of them.getchar()
callsread()
on stdin. There's now no bytes in the buffer so you block waiting for input, the same as before. The previousCtrl+D
was already "used up" to end the previousread()
call so it doesn't matter any more.Ctrl+D
.read()
returns zero.getchar()
sees this and returnsEOF
.In the above case
Ctrl+D
doesn't work as expected because of the line buffering. Theread()
call ended early without waiting as expected, but your program just starts receiving all the buffered input so it doesn't have any idea you pressedCtrl+D
and never gets theread() == 0
EOF condition. Additionally theCtrl+D
is a one-time deal, it ends oneread()
call early and sends the buffered input. When you callread()
again with nothing to send it just blocks and you have to do anotherCtrl+D
to actually getread()
to return zero.You can see the line buffering behavior if you add a
putchar()
inside your loop. Theputchar()
doesn't actually print while you type the characters, it only prints after you hit either enter orCtrl+D
, showing that your program did not receive any of the characters until one of those two actions happened.Thanks a lot for the in depth explanation, this makes things a lot clearer. I'll try 'putchar()' and test a few more things and then come back to read this post again