C - Standard Output Printing Order - c

The code is as follows:
printf("u");
write(STDOUT_FILENO, "m", 1);
printf("d\n");
output: mud
Can someone explain why the output is printed in this order?

The standard output is line buffered by default, that means printf("u"), will only put the "u" in its buffer, until a fflush or a new line character is seen. To see the output in order, try this:
printf("u");
fflush(stdout);
write(STDOUT_FILENO, "m", 1);
printf("d\n");

printf stores "u" in a buffer. write writes data to the underlying filedescritor. The next printf puts "d\n" in the buffer. At some point in the future (either when the program exits, or when you call printf enough that the buffer is full), the buffer will be written to the underlying file descriptor.

Output via the standard C streams is buffered. The first call to printf stored u into the buffer, while the second line outputs an m directly to the system's standard output file handle via the write system call, finally the second call to printf stores d and a line feed in the buffer and flushes the buffer to the system standard output handle, either because output is line buffered (which is usually the default if the FILE* is associated with a terminal) and \n causes the flush or because the stream is flushed upon program normal termination.
stderr is unbuffered by default, try this:
fprintf(stderr, "u");
write(STDERR_FILENO, "m", 1);
fprintf(stderr, "d\n");

Related

C - fdopen gives a stream for STDOUT_FILENO that doesn't work with fflush

When I run the following C code on a Linux system:
printf("This is sentence 1. ");
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
I get the output in a wrong order:
This is sentence 2.
This is sentence 1.
I understand that this happens because 'printf' sends the data to a buffer in the user space, and it takes some time to get to the kernel space, while 'write' sends the data immediately to the cache buffer in the kernel space.
A way to fix this is by flushing the data from user-space buffer to kernel-space buffer this way:
printf("This is sentence 1. ");
fflush(stdout);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
And then the correct output is received:
This is sentence 1. This is sentence 2.
Another way that I tried to solve this issue is by trying to get the stdout stream from the STDOUT_FILENO fd:
FILE *file = fdopen(STDOUT_FILENO, "w");
printf("This is sentence 1. ");
fflush(file);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
But, I get the output in the wrong order:
This is sentence 2.
This is sentence 1.
In order to make sure that STDOUT_FILENO is a fd that represents stdout, I converted stdout to a fd:
int fd = fileno(stdout);
if(fd == STDOUT_FILENO)
printf("fd == STDOUT_FILENO == %d\n", fd);
And received the expected output:
fd == STDOUT_FILENO == 1
So, the question is why when converting STDOUT_FILENO to a stream that should be equivalent to stdout, the 'fflush' function doesn't work? Is there a problem with the way I use 'fdopen'?
The buffer is a property of the stdio stream, that is, the FILE structure. printf is always printing to stdout, so it's the stdout stream you need to call fflush on. When you wrote
FILE *file = fdopen(STDOUT_FILENO, "w");`
, that gave you a second, completely independent FILE stream, with its own buffer. But you don't print anything to that stream, so falling fflush on it accomplishes nothing, and meanwhile, the text you printfed to stdout remains unflushed.
If you've got buffered output on stdout, it's stdout you must call fflush on. (Or, alternatively, add a \n at the end of the string you print with printf, since stdout is typically line-buffered, at least if it's going to a terminal.)
In this:
FILE *file = fdopen(STDOUT_FILENO, "w");
printf("This is sentence 1. ");
fflush(file);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
printf does not send anything to file. It writes to stdout.
Each FILE object contains its own buffer (whether directly or via pointer to allocated memory). When you execute printf("This is sentence 1. ");, it writes to the buffer in the stdout FILE. When you fflush(file);, it flushes the buffer in file.
To make this work, you could write fprintf(file, "This is sentence 1. ");, since that will write to the buffer in file, and fflush(file); will flush it.

why the execution order of output is not as expected

I'm learning c and I got stuck in some codes as below from a tutorial.
#include <stdio.h>
int main() {
fprintf(stdout, "This is to stdout. ");
fprintf(stderr, "This is to stderr. ");
fprintf(stdout, "This is also to stdout. ");
}
and the result they got is
This is to stderr. This is to stdout. This is also to stdout.
which is out of order
but what I got is
This is to stdout. This is to stderr. This is also to stdout.
which is in order.
So that's so weird, Why I got a different result?
(the tut I refer to is https://www.journaldev.com/39049/fflush-in-c)
Maybe in your implementation, stdout is unbuffered. Check your documentation.
You may want to try setvbuf() to revert stdout to line-buffered: use, for example, setvbuf(stdout, 0, _IOLBF, 1000); right at the beginning of main() before any other use of stdout.
Usually stdout is line-buffered and stderr is unbuffered.
unbuffered : data is sent, by the OS, from the stream to the device as soon as it is available.
line-buffered: data is sent to the device when a newline (or a limit) is reached.
fully buffered: data is sent to the device when the buffer is full.
fprintf(stdout, "hello"); // "hello" is kept in buffer because no newline
fprintf(stderr, "again"); // "again" is sent to the device immediately
fprintf(stdout, "world"); // "world" is kept in buffer
// ...
return 0; // buffer (now containing "helloworld") is sent to the device at program completion

stdout stream changes order after redirection?

These days I was learning the "apue", a result of an typical case confused me. The following are the sample codes of "sample.c":
#include "apue.h"
#include <stdio.h>
#define BUFF_SZ 4096
int main()
{
int n = 0;
char buff[BUFF_SZ] = {'\0'};
while ((n = read(STDIN_FILENO, buff, BUFF_SZ)) > 0) {
printf("read %d bytes\n", n);
if (write(STDOUT_FILENO, buff, n) != n) {
err_sys("write error");
}
}
if (n < 0) {
err_sys("read error");
}
return 0;
}
After compilation gcc sample.c, you can use this command echo Hello | ./a.out and get the following std output on terminal:
read 6 bytesHello
However, if you redirect the output to a file echo Hello | ./a.out > outfile, then use cat outfile to see the content:
Helloread 6 bytes
The ouput changes order after redirection! I wonder if some one could tell me the reason?
For the standard I/O function printf, when you output to a terminal, the standard output is by default line buffered.
printf("read %d bytes\n", n);
\n here cause the output to flush.
However, when you output to a file, it's by default fully buffered. The output won't flush unless the buffer is full, or you explicitly flush it.
The low level system call write, on the other hand, is unbuffered.
In general, intermixing standard I/O calls with system calls is not advised.
printf(), by default, buffers its output, while write() does not, and there is no synchronisation between then.
So, in your code, it is possible that printf() stores its data in a buffer and returns, then write() is called, and - as main() returns, printf()s buffer is flushed so that buffered output appears. From your description, that is happening when output is redirected.
It is also possible that printf() writes data immediately, then write() is called. From your description, that happens when output is not redirected.
Typically, one part of redirection of a stream is changing the buffer - and therefore the behaviour when buffering - for streams like stdout and stdin. The precise change depends on what type of redirection is happening (e.g. to a file, to a pipe, to a different display device, etc).
Imagine that printf() writes data to a buffer and, when flushing that buffer, uses write() to produce output. That means all overt calls of write() will have their output produced immediately, but data that is buffered may be printed out of order.
The problem is that the writes are handled by write(2) call, so you effectively lose control of what happens.
If we look at the documentation for write(2) we can see that the writes are not guaranteed to be actually written until a read() occurs. More specifically:
A successful return from write() does not make any guarantee that data has
been committed to disk. In fact, on some buggy implementations, it does not even
guarantee that space has successfully been reserved for the data. The only way to
be sure is to call fsync(2) after you are done writing all your data.
This means that depending on the implementation and buffering of the write(2) (which may differ even between redirects and printing to screen), you can get different results.

C/Unix Strange behaviour while using system calls and printf

I'm a newbie, trying to really understand systems programming. In the following program, I'm reading a file called 'temp1' (containing 1 2 3 4) and printing its contents to stdout. However, I also wanted to check the value of file descriptor returned by open. If I include the '\n' in printf call on line 5, the output prints value filep first and then contents of file. But if I remove the newline, the contents of file get printed first and then the value of filep.
Why would this happen ?
int main(){
char buf[BUFSIZ];
int n, filep;
// Open the file
filep = open("temp1", 'r');
printf("%d\n", filep); // the newline alters program behaviour
while((n=read(filep, buf, BUFSIZ)) > 0)
write(1, buf, n);
return 0;
}
I am using gcc 4.6.3.
<stdio.h> functions like printf are buffered. Output functions will call the write(2) syscall only from time to time, usually output functions like printf etc... are going only into the internal FILE buffer.
The stdout is line-buffered when outputting to a terminal (see isatty(3)). So if a printf format string ends with \n the write will occur.
You could add a fflush(stdout); or fflush(NULL); call before your while loop.
See fflush(3) and setvbuf(3)
If you don't flush stdout (either with a \n in printf format string, or explicitly thru fflush or fclose) the buffer is flushed only at the end of main (thru some implicit atexit(3) ...)
So what is happening to you is that (without the \n) data stays in the stdout buffer, and is actually written (by the write(2) inside stdio library) only at the exit of your program.
Read advanced linux programming.

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