Reputation: 470
While working on a project in C and gcc, I've come up on something quite strange I can't understand. The following code should print the value of i, at least once, but for some reason, on Linux and gcc (also g++), it does not, it just hangs without outputting anything. Note printf does indeed work in other scenarios.
#include <stdio.h>
int main() {
int i;
int j;
int z;
for (i = 0; i < 47966; i++) {
printf("%d ", i);
for (j = 0; j < 47966; j++) {
for (z = 0; z < 47966; z++) {
}
}
}
return 0;
}
Has anyone encountered this? Why is this happening?
Upvotes: 0
Views: 364
Reputation: 1600
There are only three cases when output is sent from the buffer to the screen:
1: It is sent when the buffer gets full.
2: When a newline character is encountered (in a line buffered terminal).
3: When there is impending input.
Unlike from what has been said by @Mogzol in the comments, if there was some buffering problem going out here then this simple single loop wouldn't have worked either:
for(i=0;i<47966;i++)
{
printf(" %d",i);
}
There is something else happening in this, step by step example:
CASE 1:
#include<stdio.h>
int main(void)
{
unsigned long int i=47966ull,k;
for(k=0;k<i;++k)
{
}
return 0;
}
This above code takes nearly negligible time to complete, although nothing is done by the loop.
CASE 2:
#include<stdio.h>
int main(void)
{
unsigned long int i=47966,k;
for(i=0;i<47966;i++)
for(k=0;k<47966;++k)
{
}
return 0;
}
This above code nearly takes 9.1 seconds (not counting the error) to run while doing nothing.
CASE 3:
#include<stdio.h>
int main(void)
{
unsigned long int i=47966,k,z;
for(i=0;i<47966;i++)
{
printf(" %d",i);
for(k=0;k<47966;++k)
{
}
}
return 0;
}
This certainly works as from case 1 we can say that for each i
the waiting time is less, hence the digits get printed soon.
Even to print this simple underlying code (you can try that), it takes a massive amount of time:
//WRITTEN TO CHECK WHEN DOES THE FIRST OVERFLOW OCCURS
#include<stdio.h>
int main(void)
{
unsigned long int i=47966,k,z;
for(i=0;i<47966;i++)
{
printf(" %d",i);
for(k=0;k<47966;++k)
{
printf("-");
}
}
return 0;
}
In the case of yours, its a massive waiting time before the first buffer overflow occurs. I have mentioned overflow because:
\n
to flush it.SOURCE(S): - What is it with printf() sending output to buffer?
NOTE: Ignore the unsigned long
part - it was just from some old program I didn't bother to change.
MAJOR--> If you use fflush(stdout)
in the inner most loop, you'll find that it is just timing issue - consuming lots of time to buffer all of them from 0 to 47966 as there would be only one number in the buffer between two consecutive flush.
Upvotes: 1
Reputation: 164939
You are likely Suffering From Buffering.
It is more efficient in most cases to write to a device in large chunks rather than in lots of little ones. Writing to a filehandle, and printf
is writing to stdout
, is typically held in a memory buffer before being sent to the actual device. That buffer must be "flushed" meaning the contents of the buffer are written to the device. There are three types of buffering: unbuffered, block buffered, and line buffered.
stderr
is typically unbuffered, every write to stderr
is immediately sent to the device. This is good because you want to see your error information right away.
Files are typically block buffered. Writes are stored in a memory buffer of BUFSIZ
and flushed when the buffer is reached or when the filehandle is closed either explicitly or when the process terminates.
stdout
is line buffered meaning it has a buffer, but automatically flushes when it sees a newline or when something is read from stdin
. This is a compromise between usability and performance, typically you want to display entire lines at a time or when you're prompting for input.
Your program never outputs a newline, so your numbers will stay in the line buffer until the buffer is full or the process terminates. Since it takes 2,300,737,156 iterations to print a single integer it'll be a while before the buffer is filled. And 110,357,158,424,696 iterations before the program terminates and automatically flushes and closes stdout
. Though if you compile it with optimizations the compiler will recognize the internal loops do nothing and eliminate them; then your code will execute and print very quickly.
You can solve this by flushing the buffer manually just after you print with fflush(stdout)
.
Upvotes: 2