Buffering stdin & stdout - c

I have this simple peace of code :
#include <stdio.h>
int main()
{
fprintf(stdout , "stdout \n");
fprintf(stderr , "stduerr \n");
return 0;
}
Output:
stdout
stderr
I know that stdout is buffered and stderr is not and know a bout newline flushing
the result on Windows and netbeans is :
stdout
stderr
the result using mac and Eclipse :
stderr
stdout
and Want to know why ...
Thanks a lot ...

stdout by default (on your system anyways) is line buffered, meaning it will flush either when you flush it, or when you put a newline character '\n' in it, which you do here:
fprintf(stdout , "stdout \n");
More on the buffering of stdout:
If stdout is known to not refer to an interactive device, the stream
is fully buffered. Otherwise, it is library-dependent whether the
stream is line buffered or not buffered by default (see setvbuf).
Source

With stdio(3) output streams that refer to terminal devices are line buffered like stdout, while stderr is not buffered.
The program above exits immediately after fprintf, so stdout is flushed then.
If you want to see the differences in behavior, redirect the stdout and stderr to a file, and add a few more fprintf lines.

As others already noted, you will get the result you expected if you use
fprintf(stdout, "STDOUT");
fprintf(stderr, "STDERR");
This is because the default Linux terminal stdout is line buffered while stderr is not buffered.
You will need to flush stdout or to manually print a '\n' to stdout before the print to stderr. Then you will see it before the stderr message.
Note that it is also possible to turn off buffering for stdout.

Related

sync c program with terminal in eclipse

Terminal is not synchronized with the program.
This is my simple code to see if it works:
#include <stdio.h>
int main(void){
puts("Hello World!");
system("pause");
return 0;
}
but in the local terminal appears
Press a key to continue...
before
Hello World!
This means that it is not synchronized with the program. How can I solve?
The problem is probably that the output buffer is not getting flushed before the function system is executed.
In order to explicitly flush the output buffer, you can add the line
fflush( stdout );
immediately before the call to system.
On most platforms, the standard output stream is line-buffered, so it should not be necessary to flush the output buffer, because puts automatically adds a newline character to the string, which should cause a line-buffered stream to be automatically flushed. However, according to the information you provided, the standard output stream does not seem to be line-buffered in Eclipse. It seems to be fully-buffered instead.

puts() doesn't flush the buffer in io redirection program

the code as follows:
int main(int argc, char **argv)
{
const char *file = "/tmp/out";
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
int stdout_tmp = dup(1);
close(1);
dup(fd);
puts("hello world!");
// fflush(stdout);
close(1);
close(fd);
dup(stdout_tmp);
puts("redirect completed!");
exit(0);
}
I compile the code succssfully without any warning using gcc10.2.0, Againest my expectation, the two line both are output to the stdout instead "hello world" in the /tmp/out file and "redirect completed!" in stdout. When uncomment the fflush(stdout), it works!
I guess that the puts() doesn't refresh the buffer in user space, after restoring the stdout and exit, the buffer is auto refreshed.
gets() output string with trailing '\n' and the stdout buffer will be auto refreshed when encounter '\n'. Why need to call fflush(stdout) manually?
The stdout file (where puts writes) is line-buffered (i.e. flushes the buffer on newline) only when connected to a terminal (basically when isatty(fileno(stdout)) is true).
When connected to another non-terminal output then it's fully buffered, which means you either need to fill the buffer completely, or call fflush explicitly to flush the buffer.
man 3 setvbuf says:
Normally all files are block buffered.
If a stream refers to a terminal (as stdout normally does), it is line buffered.
Since puts() uses stdout we should expect a flush
(because of the \n).
However, since in your example stdout has not been used before
the redirection, I guess that the buffering behaviour is not chosen
yet.
At your first write attempt to stdout, the underlying file descriptor
is not a terminal anymore but a regular file.
I guess the buffering behaviour is chosen at this moment.
If you add another call to puts() in your example before the
redirection, then the buffering behaviour is chosen for the terminal
and then does not change afterwards when the redirection is performed.
In this case, your example works as you expect (without the explicit
fflush()).
edit
Still in man 3 setvbuf:
When the first I/O operation occurs on a file, malloc(3) is called, and a buffer is obtained.
and further:
The setvbuf() function may only be used after opening a stream and before any other operations have been performed on it.
On linux, this is consistent with your example.
In the MSDN page for setvbuf:
stream must refer to an open file that has not undergone an I/O operation since it was opened.

Why would I need use fflush on stdout before writing to stderr?

I am reading 'UNIX Network Programming: The Sockets Networking API' and in the example code they have an error handling function which contains the following lines:
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);
Where buf contains the error description. I don't understand why fflush is used on stdout on the first line and why the comment explains the reason for its use.
This is because of buffering. Stdout and stderr are usually buffered differently. Stdout is usually line buffered, meaning it will not display output until it sees a newline. Stderr is usually unbuffered and will print immediately, the thinking is you should see error messages pronto.
But they both go to the same place, the terminal. This is what it means by /* in case stdout and stderr are the same */. They usually are. But because they're buffered differently this can lead to them being displayed out of order.
Consider this code. Note the lack of a newlines.
#include <stdio.h>
int main() {
fprintf(stdout, "This is to stdout. ");
fprintf(stderr, "This is to stderr. ");
fprintf(stdout, "This is also to stdout. ");
}
You'd expect the output to be:
This is to stdout. This is to stderr. This is also to stdout.
But it isn't. It's out of order.
$ ./test
This is to stderr. This is to stdout. This is also to stdout.
The output to stderr is displayed immediately, it is unbuffered. While stdout has to wait until the stdout buffer is flushed by a newline. There is no newline, so it is flushed when the program exits.
By flushing stdout before you use stderr you ensure that the output comes in the right order regardless of buffering.
#include <stdio.h>
#include <unistd.h>
int main() {
fprintf(stdout, "This is to stdout. ");
fflush(stdout);
fprintf(stderr, "This is to stderr. ");
fprintf(stdout, "This is also to stdout. ");
}
$ ./test
This is to stdout. This is to stderr. This is also to stdout.
This ensures that error messages come out in the right order along with normal messages. This avoids confusion about what error message applies to what part of the program.
If stdout and stderr point to the same file, you have to be sure that whatever is in the stdout buffer is written first.

why doesn't this c programme print the first printf statement?

#include<stdio.h>
#include <unistd.h>
int main(){
while(1)
{
fprintf(stdout,"hello-out");
fprintf(stderr,"hello-err");
sleep(1);
}
return 0;
}
On compiling this programme in gcc and on executing it only prints hello-err and not hello-out.Why is that so?Can someone please explain the reason behind it?
If you add a '\n' to your message it will (or should), ie. "hello-out\n".
The reason being is that stdout is buffered in order to be more efficient, whereas stderr doesn't buffer it's output and is more appropriate for error messages and things that need to be printed immediately.
stdout will usually be flushed when:
A newline (\n) is to be printed
You read in from stdin
fflush() is called on it
EDIT: The other thing I wanted to add before my computer crashed...twice...was that you can also use setbuf(stdout, NULL); to disable buffering of stdout. I've done that before when I've had to use write() (Unix) and didn't want my output to be buffered.
It doesn't always print out the output to stdout because by design stdout is BUFFERED output, and stderr is unbuffered. In general, the for a buffered output stream, the stream is not dumped until the system is "free" to do so. So data can continue buffering for a long while, before it gets flushed. If you want to force the buffer to flush you can do so by hand using fflush
#include<stdio.h>
#include <unistd.h>
int main(){
while(1)
{
fprintf(stdout,"hello-out");
fflush(stdout); /* force flush */
fprintf(stderr,"hello-err");
sleep(1);
}
return 0;
}
Update: stdout is linebuffered when connected to a terminal, and simply buffered otherwise (e.g. a redirect or a pipe)
You forgot newlines (noted \n) in your strings. Or you need to call fflush(NULL); or at least fflush(stdout); before sleep(1);
And fprintf(stdout, ...) is the same as printf(...)
You need to output newlines or to call fflush because (at least on Linux) the stdout FILE buffer is line-buffered. This means that the C library is buffering data, and will really output it (using the write Linux system call) when the buffer is full enough, or when you flush it either with a new line, or by calling fflush. Buffering is needed because system calls are costly (calling write for every byte to be output is really too slow). Read also the man page of setbuf

Whats wrong with this print order

have a look at this code:
#include<stdio.h>
#include <unistd.h>
int main()
{
int pipefd[2],n;
char buf[100];
if(pipe(pipefd)<0)
printf("Pipe error");
printf("\nRead fd:%d write fd:%d\n",pipefd[0],pipefd[1]);
if(write(pipefd[1],"Hello Dude!\n",12)!=12)
printf("Write error");
if((n=read(pipefd[0],buf,sizeof(buf)))<=0)
printf("Read error");
write(1,buf,n);
return 0;
}
I expect the printf to print Read fd and write fd before Hello Dude is read from the pipe. But thats not the case... see here. When i tried the same program in our college computer lab my output was
Read fd:3 write fd:4
Hello Dude!
also few of our friends observed that, changing the printf statement to contain more number of \n characters changed the output order... for example..printf("\nRead fd:%d\n write fd:%d\n",pipefd[0],pipefd[1]); meant that Read fd is printed then the message Hello Dude! then the write fd is printed. What is this behaviour??
Note: Out lab uses a linux server on which we run terminals, i don't remember the compiler version though.
It's because printf to the standard output stream is buffered but write to the standard output file descriptor is not.
That means the behaviour can change based on what sort of buffering you have. In C, standard output is line buffered if it can be determined to be connected to an interactive device. Otherwise it's fully buffered (see here for a treatise on why this is so).
Line buffered means it will flush to the file descriptor when it sees a newline. Fully buffered means it will only flush when the buffer fills (for example, 4K worth of data), or when the stream is closed (or when you fflush).
When you run it interactively, the flush happens before the write because printf encounters the \n and flushes automatically.
However, when you run it otherwise (such as by redirecting output to a file or in an online compiler/executor where it would probably do the very same thing to capture data for presentation), the flush happens after the write (because printf is not flushing after every line).
In fact, you don't need all that pipe stuff in there to see this in action, as per the following program:
#include <stdio.h>
#include <unistd.h>
int main (void) {
printf ("Hello\n");
write (1, "Goodbye\n", 8);
return 0;
}
When I execute myprog ; echo === ; myprog >myprog.out ; cat myprog.out, I get:
Hello
Goodbye
===
Goodbye
Hello
and you can see the difference that the different types of buffering makes.
If you want line buffering regardless of redirection, you can try:
setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
early on in your program - it's implementation defined whether an implementation supports this so it may have no effect but I've not seen many where it doesn't work.
You shouldn't mix calls to write and printf on single file descriptor. Change write to fwrite.
Functions which use FILE are buffered. Functions which use file descriptors are not. This is why you may get mixed order.
You can also try calling fflush before write.
When you write onto the same file, or pipe, or whatever by two means at once (direct IO and output stream) you can get this behaviour. The reason is that the output stream is buffered.
With fflush() you can control that behaviour.
What is happening is that printf writes to stdout in a buffered way -- the string is kept in a buffer before being output -- while the 'write' later on writes to stdout unbuffered. This can have the effect that the output from 'write' appears first if the buffer from the printf is only flushed later on.
You can explicitly flush using fflush() -- but even better would be not to mix buffered and non-buffered writes to the same output. Type man printf, man fflush, man fwrite etc. on your terminal to learn more about what these commands do exactly.

Resources