Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What is the problem with this piece of code?

191 views
Skip to first unread message

Alexander

unread,
Sep 17, 2010, 11:50:30 AM9/17/10
to
In my idea it should:
- get the current time
- print 'a'
- do nothing until a second passes
- print 'b':
and repeat for eternity. Instead, it does nothing, and the program
does not exit (probably enters into an infinite loop without producing
any input).

Thanks!

#include <stdio.h>
#include <time.h>

int main() {
char c = 'a';
while(1) {
time_t startTime = time(NULL);
putchar(c);
if (c < 'z') c++;
else c = 'a';
while(startTime == time(NULL));
}
}

Mara Guida

unread,
Sep 17, 2010, 12:01:51 PM9/17/10
to
On Sep 17, 4:50 pm, Alexander <alva...@gmail.com> wrote:
> In my idea it should:
>   - get the current time
>   - print 'a'

You need to flush the output stream (or print a line break) to see the
output.
Try fflush(stdout) soewhere inside your loop.

Alexander

unread,
Sep 17, 2010, 12:29:00 PM9/17/10
to
Ok, thanks. I wasn't aware that when I call an output function, it's
not immediately applied.

Keith Thompson

unread,
Sep 17, 2010, 12:47:06 PM9/17/10
to

It's already been pointed out that output buffering is the problem.

I'll also point out a couple of assumptions you're making.

On many systems, time() returns an integer representing the number
of seconds since a fixed point in the past, so its value changes once
per second, but the standard doesn't guarantee that. If time() has a
finer resolution (for example, if time_t is a floating-point type or
represents a count of milliseconds), you might get a lot more output
that you expect. Note that the resolution of the type time_t doesn't
necessarily match the resolution of the values returned by time().
You're not very likely to run into a system where this is an issue.

The standard doesn't guarantee that the values of 'a' through 'z'
are contiguous. If you were on an EBCDIC system, for example,
you'd see some other characters, some of them undefined, between
some of the letters. Again, unless you work with IBM mainframes,
you're unlikely to run into this.

The first iteration of the loop will take less than a second,
depending on when you start the program.

Your busy loop:

while(startTime == time(NULL));

could cause your program to consume a great deal of CPU time.
This could be bad if you're on a multi-user, or even multi-process,
system.

Finally, just because I can't help myself, "int main()" is better
written as "int main(void)".

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Kenneth Brody

unread,
Sep 17, 2010, 12:54:53 PM9/17/10
to
On 9/17/2010 12:29 PM, Alexander wrote:
> Ok, thanks. I wasn't aware that when I call an output function, it's
> not immediately applied.

Well, the putchar(c) is "immediately applied". However, FILEs can use
buffered I/O, and stdout, by default, uses "line buffering", meaning that
the output buffer isn't flushed until a newline is encountered, or when the
output buffer is full.

By adding an explicit fflush(stdout) or putchar('\n') after the putchar(c),
you explicitly force the buffer to be flushed for every character.

Otherwise, after some amount of time, the buffer would be filled, and it
would be implicitly flushed. However, the buffer size on my implementation
is 512, meaning it would take 512 seconds before that were to happen here.
And, as I have seen buffer sizes of 4K, such a system would take over an hour.

--
Kenneth Brody

Nobody

unread,
Sep 18, 2010, 2:58:26 AM9/18/10
to
On Fri, 17 Sep 2010 12:54:53 -0400, Kenneth Brody wrote:

>> Ok, thanks. I wasn't aware that when I call an output function, it's
>> not immediately applied.
>
> Well, the putchar(c) is "immediately applied". However, FILEs can use
> buffered I/O, and stdout, by default, uses "line buffering",

Unix convention is that stdin and stdout are line-buffered when associated
with a terminal, and fully-buffered (aka block-buffered) otherwise. stderr
is always unbuffered.

The ISO C standard is slightly less specific; 7.19.3.p7:

As initially opened, the standard error
stream is not fully buffered; the standard input and
standard output streams are fully buffered if and only if
the stream can be determined not to refer to an interactive
device.

POSIX mirrors the ISO C definition, but all real Unices (SysV, BSD,
Linux) follow the stricter convention.

Jorgen Grahn

unread,
Sep 18, 2010, 11:47:24 AM9/18/10
to
On Fri, 2010-09-17, Keith Thompson wrote:
...

> Your busy loop:
>
> while(startTime == time(NULL));
>
> could cause your program to consume a great deal of CPU time.
> This could be bad if you're on a multi-user, or even multi-process,
> system.

Or even a single-process system where wasting cycles means wasting
battery life, global warming and other nastiness ...

(He probably knew already that busy loops are a bad idea, but perhaps he
should have mentioned that he knew.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Morris Keesan

unread,
Sep 19, 2010, 11:39:51 PM9/19/10
to
On Fri, 17 Sep 2010 12:54:53 -0400, Kenneth Brody <kenb...@spamcop.net>
wrote:

...


> Well, the putchar(c) is "immediately applied". However, FILEs can use
> buffered I/O, and stdout, by default, uses "line buffering", meaning
> that the output buffer isn't flushed until a newline is encountered, or
> when the output buffer is full.
>
> By adding an explicit fflush(stdout) or putchar('\n') after the
> putchar(c), you explicitly force the buffer to be flushed for every
> character.

It would be simpler to call setbuf(stdout, NULL) before starting any of
the output, instead of having multiple calls to fflush().

--
Morris Keesan -- mke...@post.harvard.edu

Kenneth Brody

unread,
Sep 20, 2010, 11:07:49 AM9/20/10
to

In this simple case, where the only output is a single putchar(). However,
consider the implications where longer strings are output between fflush()es.

--
Kenneth Brody

Kenneth Brody

unread,
Sep 20, 2010, 11:14:04 AM9/20/10
to

Drifting into mildly OT territory, since this is partially
implementation-specific. However, I have run into the distinction between
"terminal" and "non-terminal" stdout streams and their buffering.

One feature of our program is the ability to open a two-way I/O stream to a
user program, send data to its stdin, and receive data from its stdout.
It's very common to get a report from a developer where it's "not working"
when run from within our program, but "works fine" when run from the command
line, with the user typing in the input, and seeing the output. I have to
explain the concepts of buffered I/O, and tell them to test it under an
environment closer to how it would be run from our program, with something like:

cat -u | their_program | cat -u

Then, they can immediately see that their program sends "no output" to the
screen until they add the necessary fflush(stdout).

--
Kenneth Brody

Keith Thompson

unread,
Sep 20, 2010, 12:16:12 PM9/20/10
to
Kenneth Brody <kenb...@spamcop.net> writes:
[...]

> I have to
> explain the concepts of buffered I/O, and tell them to test it under an
> environment closer to how it would be run from our program, with something like:
>
> cat -u | their_program | cat -u
>
> Then, they can immediately see that their program sends "no output" to the
> screen until they add the necessary fflush(stdout).

I think somebody already mentioned that the GNU coreutils version of
"cat" ignores the "-u" option.

0 new messages