main() does not return when getchar() reaches EOF

S

Seeker

I essentially copied this program from K&R:

#include <stdio.h>
#include <stdlib.h>

int main()
{

int c;

while ((c=getchar())!=EOF)
putchar(c);

return 0;
}



When I run it it takes my input and prints it on the console but
doesn't exit. The program continues running. No matter what I input
it always continues running.

This is Dev-C++, uses gcc. Is it a compiler problem?
 
A

Alf P. Steinbach

* Seeker:
I essentially copied this program from K&R:

#include <stdio.h>
#include <stdlib.h>

int main()
{

int c;

while ((c=getchar())!=EOF)
putchar(c);

return 0;
}



When I run it it takes my input and prints it on the console but
doesn't exit. The program continues running. No matter what I input
it always continues running.

This is Dev-C++, uses gcc. Is it a compiler problem?

No, it is a user problem. Specifically, you never generate an end of
file. In Unix, use Ctrl D to submit zero bytes, which is then
interpreted as end of file; in Windows, use Ctrl Z followed by return,
where the control character itself is interpreted as end of file.
 
S

Seeker

No, it is a user problem. Specifically, you never generate an
end of file. In Unix, use Ctrl D to submit zero bytes, which is
then interpreted as end of file; in Windows, use Ctrl Z followed
by return, where the control character itself is interpreted as
end of file.

I see. Thanks.
 
K

Keith Thompson

Alf P. Steinbach said:
* Seeker:

No, it is a user problem. Specifically, you never generate an end of
file. In Unix, use Ctrl D to submit zero bytes, which is then
interpreted as end of file; in Windows, use Ctrl Z followed by return,
where the control character itself is interpreted as end of file.

<OT>
I'm not sure what you mean by "submit zero bytes", but I don't believe
that's what it does.
</OT>
 
K

Kenny McCormack

Keith Thompson said:
<OT>
I'm not sure what you mean by "submit zero bytes", but I don't believe
that's what it does.

Actually, that is exactly what it does.
 
D

Dik T. Winter

> In article <[email protected]>,

>
> Actually, that is exactly what it does.

That is actually exactly not what it does. ^D under Unix/Linux generates
an out of band EOF signal when used as the first character on a line on
console input. A double ^D does the same when not the first character.
 
C

Chris Torek

Alf P. Steinbach said:
... you [need to] generate an end of file [from keyboard input].
In Unix, use Ctrl D to submit zero bytes, which is then
interpreted as end of file; in Windows, use Ctrl Z followed by return,
where the control character itself is interpreted as end of file.

<OT>
I'm not sure what you mean by "submit zero bytes", but I don't believe
that's what it does.
</OT>

This is indeed off topic, but I will take a dollar out of the
metaphorical jar. :)

On a Unix-like system, keyboard input is routed through an
interpretation layer, often called a "tty driver" for historical
reasons. This interpretation layer has several modes, usually
called "cooked", "cbreak", and "raw". In "raw" mode all input
characters are passed through immediately and unchanged. In
"cbreak" mode, most characters are passed through immediately and
unchanged; a few are interpreted specially. In the most usual,
"cooked" mode, however, characters are collected up for input
editing, allowing the user to erase incorrect input, up to a point.

In cooked mode, there are a number of user-specified special
characters, including one called the "EOF character". This is
normally set to control-D. Internally, however, it is not really
an "EOF character" at all. Instead, it has almost the same
effect as pressing the ENTER or RETURN key.

The key labeled ENTER (or RETURN) usually sends a control-M to
the connected serial port. What? Oh, right, we have another
historical artifact here.

Modern keyboards send key-up/key-down codes over some sort of
connection (often, now, a USB or wireless channel). However, on
a typical Unix-like system, a software layer translates these
into what look like serial-port signals coming from an old-style
terminal device. These old-style terminal devices, common back
in the 1980s, would send control-M when you pushed ENTER.

Anyway, back to the "tty driver" software layer: when it sees a
control-M (in cooked mode), it translates it to a control-J (or
"line feed" or '\n') character. Then it falls through to the code
that handles a control-J. This code puts the control-J into the
edit buffer, and then sends the current contents of the edit buffer
up through the rest of the system's software layers, to be returned
from a read() system call and delivered to -- in this case -- your
program using C's "stdin" stream.

Most other ordinary characters simply go into the edit buffer, and
are (optionally) echoed back to the output serial port -- which,
in many cases today, is another fake, made out of yet another
software layer that connects to a display of some sort, or reroutes
to a window system, or some such; but that is yet another can of
worms. There they sit, waiting to be edited (deleted or added-to
or whatever) until you press ENTER.

If you press the EOF key (normally control-D), however, the tty
driver does almost the same thing that it does for control-J. For
control-J, it adds the '\n' to the edit buffer and sends the
contents back up the layers. For control-D, it skips the "add"
part, and sents the buffer contents up. IF THE BUFFER IS EMPTY,
this causes the read() system call to return 0. If the buffer
is *not* empty, the read() system call returns some positive
number, and C's "stdin" stream collects up a sequence of characters
that does *not* end with a '\n'.

Whenever a read() system call returns 0, a Unix-like system's stdio
interprets that as "end of input", and delivers an EOF from the
stream. So pressing ^D does, in this case, "submit zero bytes",
as long as you press it with an empty cooked-mode edit buffer.
 
K

Kenny McCormack

That is actually exactly not what it does. ^D under Unix/Linux generates
an out of band EOF signal when used as the first character on a line on
console input. A double ^D does the same when not the first character.

Wrong. The phrase "submit zero bytes" (although worded a little
strangely, but we're used to this "pigeon English" around here) is quite
accurate.

This is all stunningly OT, of course, but all you have to do is check
the return value from read() (Yes, it is OT, we know that) to get the point.

It really, really, isn't any kind of "out of band" signal.
 
S

Skarmander

Kenny said:
Wrong. The phrase "submit zero bytes" (although worded a little
strangely, but we're used to this "pigeon English" around here) is quite
accurate.

This is all stunningly OT, of course, but all you have to do is check
the return value from read() (Yes, it is OT, we know that) to get the point.

It really, really, isn't any kind of "out of band" signal.

As Chris' post excellently explained, you're both right. Or wrong, as the
case may be. ^D really is out-of-band for some meanings of "out-of-band"
(since the upper layers never see it) and in some way it really does cause
zero bytes to be transmitted.

Drinks for everyone.

S.
 
J

Joe Wright

Chris said:
Alf P. Steinbach said:
... you [need to] generate an end of file [from keyboard input].
In Unix, use Ctrl D to submit zero bytes, which is then
interpreted as end of file; in Windows, use Ctrl Z followed by return,
where the control character itself is interpreted as end of file.

<OT>
I'm not sure what you mean by "submit zero bytes", but I don't believe
that's what it does.
</OT>

This is indeed off topic, but I will take a dollar out of the
metaphorical jar. :)

On a Unix-like system, keyboard input is routed through an
interpretation layer, often called a "tty driver" for historical
reasons. This interpretation layer has several modes, usually
called "cooked", "cbreak", and "raw". In "raw" mode all input
characters are passed through immediately and unchanged. In
"cbreak" mode, most characters are passed through immediately and
unchanged; a few are interpreted specially. In the most usual,
"cooked" mode, however, characters are collected up for input
editing, allowing the user to erase incorrect input, up to a point.

In cooked mode, there are a number of user-specified special
characters, including one called the "EOF character". This is
normally set to control-D. Internally, however, it is not really
an "EOF character" at all. Instead, it has almost the same
effect as pressing the ENTER or RETURN key.

The key labeled ENTER (or RETURN) usually sends a control-M to
the connected serial port. What? Oh, right, we have another
historical artifact here.

Modern keyboards send key-up/key-down codes over some sort of
connection (often, now, a USB or wireless channel). However, on
a typical Unix-like system, a software layer translates these
into what look like serial-port signals coming from an old-style
terminal device. These old-style terminal devices, common back
in the 1980s, would send control-M when you pushed ENTER.

Anyway, back to the "tty driver" software layer: when it sees a
control-M (in cooked mode), it translates it to a control-J (or
"line feed" or '\n') character. Then it falls through to the code
that handles a control-J. This code puts the control-J into the
edit buffer, and then sends the current contents of the edit buffer
up through the rest of the system's software layers, to be returned
from a read() system call and delivered to -- in this case -- your
program using C's "stdin" stream.

Most other ordinary characters simply go into the edit buffer, and
are (optionally) echoed back to the output serial port -- which,
in many cases today, is another fake, made out of yet another
software layer that connects to a display of some sort, or reroutes
to a window system, or some such; but that is yet another can of
worms. There they sit, waiting to be edited (deleted or added-to
or whatever) until you press ENTER.

If you press the EOF key (normally control-D), however, the tty
driver does almost the same thing that it does for control-J. For
control-J, it adds the '\n' to the edit buffer and sends the
contents back up the layers. For control-D, it skips the "add"
part, and sents the buffer contents up. IF THE BUFFER IS EMPTY,
this causes the read() system call to return 0. If the buffer
is *not* empty, the read() system call returns some positive
number, and C's "stdin" stream collects up a sequence of characters
that does *not* end with a '\n'.

Whenever a read() system call returns 0, a Unix-like system's stdio
interprets that as "end of input", and delivers an EOF from the
stream. So pressing ^D does, in this case, "submit zero bytes",
as long as you press it with an empty cooked-mode edit buffer.

Another fine example of why we should all read whatever Chris Torek
writes. Thank you Chris.
 
S

Simon Biber

Keith said:
<OT>
I'm not sure what you mean by "submit zero bytes", but I don't believe
that's what it does.
</OT>

This is how I understand it: If you type a line of text and terminate it
with Ctrl-D instead of a carriage return, it submits what you have typed
so far, without a newline character. Thus Ctrl-D can be seen as a
command to submit what has been typed so far. If you press Ctrl-D at the
beginning of a line, when there is nothing to submit, that can be seen
as submitting zero bytes. The terminal driver's response to submission
of zero bytes is to indicate end of file.
 
?

=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=

Kenny said:
Wrong. The phrase "submit zero bytes" (although worded a little
strangely, but we're used to this "pigeon English" around here) is quite
accurate.
No. Typically the unix (which is what we are discussing) tty driver
captures various keystrokes and translate them to signals/condition/
internal tty layer manipulation. ctrl+d is usually just hooked up
to generate EOF to the reading end of the tty - pseudo tty mostly these
days..
 
K

Kenny McCormack

Simon Biber said:
This is how I understand it: If you type a line of text and terminate it
with Ctrl-D instead of a carriage return, it submits what you have typed
so far, without a newline character. Thus Ctrl-D can be seen as a
command to submit what has been typed so far. If you press Ctrl-D at the
beginning of a line, when there is nothing to submit, that can be seen
as submitting zero bytes.

So far, so good. (Of course, this is all Unix (-like) specific, so all
the usual blah, blah, blah applies as far as topicality)
The terminal driver's response to submission
of zero bytes is to indicate end of file.

But here is where you've driven off the road. The "terminal driver"
does not "indicate" end of file. All it does is return a count of 0
(which is where you were headed up above) and the program (or, to be
more precise, the layer above the read()) call sees that 0 and
interprets it (at its own risk) as an indication of "end of file".
 
K

Kenny McCormack

Nils O. Selåsdal said:
No. Typically the unix (which is what we are discussing) tty driver
captures various keystrokes and translate them to signals/condition/
internal tty layer manipulation. ctrl+d is usually just hooked up
to generate EOF to the reading end of the tty - pseudo tty mostly these
days..

Wrong. Be sure to pick up your lovely parting gifts on your way out.
 
A

Alf P. Steinbach

* Nils O. Selåsdal:
No. Typically the unix (which is what we are discussing) tty driver
captures various keystrokes and translate them to signals/condition/
internal tty layer manipulation. ctrl+d is usually just hooked up
to generate EOF to the reading end of the tty - pseudo tty mostly these
days..

Although off-topic, since it was my (accurate) comment that started
this: you have just argued that you cannot affect the speed of a car
using the gas pedal, because for one particular car you know about it's
the motor (and brakes) that directly effects changes of speed. Well, to
be really accurate you should get down to the level of interactions
between the wheels and the ground, that's where the real (tr)action is.
So, what about /voltages/ when you hit Ctrl D -- how relevant is
that, and how general are comments about detailed voltages, do you think?
 
K

Kenneth Brody

Kenny said:
But here is where you've driven off the road. The "terminal driver"
does not "indicate" end of file. All it does is return a count of 0
(which is where you were headed up above) and the program (or, to be
more precise, the layer above the read()) call sees that 0 and
interprets it (at its own risk) as an indication of "end of file".

According to the man pages here, the EOF character does the following
from a "terminal":

EOF Special character on input and is recognized if the ICANON flag
is set. When received, all the bytes waiting to be read are
immediately passed to the process, without waiting for a newline,
and the EOF is discarded. Thus, if there are no bytes waiting
(that is, the EOF occurred at the beginning of a line), a byte
count of zero is returned from the read(), representing an end-
of-file indication. If ICANON is set, the EOF character is dis-
carded when processed.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Keith Thompson

Simon Biber said:
This is how I understand it: If you type a line of text and terminate
it with Ctrl-D instead of a carriage return, it submits what you have
typed so far, without a newline character. Thus Ctrl-D can be seen as
a command to submit what has been typed so far. If you press Ctrl-D at
the beginning of a line, when there is nothing to submit, that can be
seen as submitting zero bytes. The terminal driver's response to
submission of zero bytes is to indicate end of file.

Ok. I interpreted "submit zero bytes" to mean "submit bytes whose
value is 0". It's clear that that's not what was meant -- but if that
*were* what control-D did, then the phrase "submit zero byte" would
have been a reasonable way to describe it.

(Since we all know what was meant, and the details are off-topic
anyway, I suggest there's no further need to debate this.)
 
K

Kenny McCormack

According to the man pages here, the EOF character does the following
from a "terminal":

EOF Special character on input and is recognized if the ICANON flag
is set. When received, all the bytes waiting to be read are
immediately passed to the process, without waiting for a newline,
and the EOF is discarded. Thus, if there are no bytes waiting
(that is, the EOF occurred at the beginning of a line), a byte
count of zero is returned from the read(), representing an end-
of-file indication. If ICANON is set, the EOF character is dis-
carded when processed.

Thank you for making my case. Well done.
 
S

Simon Biber

Kenny said:
So far, so good. (Of course, this is all Unix (-like) specific, so all
the usual blah, blah, blah applies as far as topicality)


But here is where you've driven off the road. The "terminal driver"
does not "indicate" end of file. All it does is return a count of 0
(which is where you were headed up above) and the program (or, to be
more precise, the layer above the read()) call sees that 0 and
interprets it (at its own risk) as an indication of "end of file".

Yes, I was misusing the term "terminal driver". By that term I meant to
include everything in between the user's keyboard and the eventual EOF
return from getchar. At some point there is an EOF generated, and that
may be by getchar / getc / fgetc themselves.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top