C/Unix Strange behaviour while using system calls and printf - c

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.

Related

Why write() executes immediately, but printf() not? [duplicate]

#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
write(1,buf,n);
}
return 1;
}
The output of the program (where the first read and first write is typed by the user and echoed by the terminal) is:
read
read
write
write
n: 5:n: 6:
The output of printf comes after pressing Ctrl+D at the standard input and not along with the subsequent reads. Why does this happen?
Printf is buffered.
You can force printf to 'flush' its buffer using the fflush call:
#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
fflush(stdout); /* force it to go out */
write(1,buf,n);
}
return 1;
}
In general, printf() being buffered is a good thing. Unbuffered output, particularly to visible consoles that require screen updates and such, is slow. Slow enough that an application that is printf'ing a lot can be directly slowed down by it (especially on the Windows platform; Linux and unixes are typically impacted less).
However, printf() being buffered does bite you if you also fprintf(stderr,) - stderr is deliberately unbuffered. As a consequence, you may get your messages with some printf() missing; if you write to another FILE handle that is also associated with the terminal, and might be unbuffered, make sure you first explicitly fflush(stdout).
The manpage for fgets tells me:
It is not advisable to mix calls to input functions from the stdio
library with low-level calls to read(2) for the file descriptor associ‐
ated with the input stream; the results will be undefined and very
probably not what you want.
So the best solution would be not to to use write and printf on the same descriptor.
Printf is using stdio and it is buffered.
Push it out by sending a changing to "n: %d:\n"
You can use the std fflush() function to flush the std out buffer or you can make use of an additional \n at the end of the control string inside the printf. Something like this
printf("\n :%d:\n",n);
Its always better to use the write() & read() functions in C instead of printf() and scanf(). Printf and scanf have got some problems like printf stores the string parameter in stdout buffer. So a manual flush is required which is done through fflush function or by means of \n. In a small hello world printing program you will not find such a problem as the stdout buffer is flushed at the end of the program execution. Better use write() which works fine. scanf also have the problem of reading spaces and a lot of other problems related to stdin buffer.
For example in the code below:
main() { char a; int i=0,c; for(;i<2;i++) { scanf("%d",&c); scanf("%c",&a);} }
The above program as got the problem of reading \n into stdin on pressing enter. We could resolve this but not flushing the stdin buffer or making use of \n character. Always better to use the read() and write() functions.
Hope that helps....
Use fwrite (streams version) rather than write.
Note that, while is associated with file number 1, it isn't the same thing.

C - Standard Output Printing Order

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");

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.

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.

write() to stdout and printf output not interleaved?

#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
write(1,buf,n);
}
return 1;
}
The output of the program (where the first read and first write is typed by the user and echoed by the terminal) is:
read
read
write
write
n: 5:n: 6:
The output of printf comes after pressing Ctrl+D at the standard input and not along with the subsequent reads. Why does this happen?
Printf is buffered.
You can force printf to 'flush' its buffer using the fflush call:
#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
fflush(stdout); /* force it to go out */
write(1,buf,n);
}
return 1;
}
In general, printf() being buffered is a good thing. Unbuffered output, particularly to visible consoles that require screen updates and such, is slow. Slow enough that an application that is printf'ing a lot can be directly slowed down by it (especially on the Windows platform; Linux and unixes are typically impacted less).
However, printf() being buffered does bite you if you also fprintf(stderr,) - stderr is deliberately unbuffered. As a consequence, you may get your messages with some printf() missing; if you write to another FILE handle that is also associated with the terminal, and might be unbuffered, make sure you first explicitly fflush(stdout).
The manpage for fgets tells me:
It is not advisable to mix calls to input functions from the stdio
library with low-level calls to read(2) for the file descriptor associ‐
ated with the input stream; the results will be undefined and very
probably not what you want.
So the best solution would be not to to use write and printf on the same descriptor.
Printf is using stdio and it is buffered.
Push it out by sending a changing to "n: %d:\n"
You can use the std fflush() function to flush the std out buffer or you can make use of an additional \n at the end of the control string inside the printf. Something like this
printf("\n :%d:\n",n);
Its always better to use the write() & read() functions in C instead of printf() and scanf(). Printf and scanf have got some problems like printf stores the string parameter in stdout buffer. So a manual flush is required which is done through fflush function or by means of \n. In a small hello world printing program you will not find such a problem as the stdout buffer is flushed at the end of the program execution. Better use write() which works fine. scanf also have the problem of reading spaces and a lot of other problems related to stdin buffer.
For example in the code below:
main() { char a; int i=0,c; for(;i<2;i++) { scanf("%d",&c); scanf("%c",&a);} }
The above program as got the problem of reading \n into stdin on pressing enter. We could resolve this but not flushing the stdin buffer or making use of \n character. Always better to use the read() and write() functions.
Hope that helps....
Use fwrite (streams version) rather than write.
Note that, while is associated with file number 1, it isn't the same thing.

Resources