Why my small C program print different string with cat utility? - c

#include <string.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
char a[6] = "abcdd";
char b[5] = "1234";
strcpy(a, b);
write(1, a, 4);
printf("AA\n");
write(1, b, 4);
printf("CC\n");
}
I was studying strcpy func.
With ./a.out
1234AA
1234CC
With ./a.out | cat -e
12341234AA$
CC$
I read man cat. Can't find any with this.
What changes can be made even after compile?
What happened?
What are the concept I am missing?

It's a buffering issue.
The write calls write directly to the standard output file descriptor. These writes are unbuffered.
The printf function writes to stdout which in normal cases (when stdout is connected to a terminal) are line-buffered (output is actually written on newline).
But when stdout is not connected to a terminal, like for example when you pipe the output, then the buffering scheme change. It becomes fully buffered. That means the buffer will only be written when explicitly flushed (or the buffer becomes full), which happens when the program exits.
Therefore the unbuffered output from write will be written first. Then when the program exits the stdout buffer will be written.
If you want the same behavior in both cases, you could explicitly flush the stdout buffer yourself:
write(STDOUT_FILENO, a, 4);
printf("AA\n");
fflush(stdout);
[Note that I changed the "magic number" 1 to the POSIX predefined symbol STDOUT_FILENO, which is typically easier to understand even when quickly glancing at the code.]

Related

Can printf write to terminal without flushing stdout?

#include <stdio.h>
int main(){
char a[2] = {0};
a[0] = 't';
printf("%s", a);
scanf("%c", a);
return 0;
}
scanf here will cause an automatic flush of stdout.
Running a.out will print t on the terminal before running scanf, more info: How is printf getting flushed before scanf is executed?
However, doing a.out > out.txt and terminating it with ^C does not print anything inside out.txt yet the output still appeared on the screen without redirecting stdout with >.
If stdout is being flushed then why out.txt is still empty?
If it's not being flushed then how did t appear on the screen in the first example?
(I know using \n or a manual fflush or properly terminating the program will fix the issue, i'm just curious about this behaviour).
The key is the word interactive:
The input and output dynamics of interactive devices shall take place as specified in 7.21.3.
As soon as you redirect the standard output to a file, it is no longer interactive.
For example the Linux C standard library actually executes the analogue of the isatty library call to figure this out. If it figures out that standard output is not directed to file it will also break this relationship. It will also increase the I/O performance of programs that work as part of a command pipeline.
You can yourself test whether stdout is connected to a terminal by executing
#include <unistd.h>
printf("stdout is connected to a terminal: %d\n", isatty(fileno(stdout)));

C: printf still not flushing before while loop, even with new line character in format string [duplicate]

This question already has answers here:
What are the rules of automatic stdout buffer flushing in C?
(5 answers)
Is stdout line buffered, unbuffered or indeterminate by default?
(1 answer)
Closed 3 years ago.
I have read many questions with people asking why printf did not work before a while loop; the answer was that it was not flushing stdout because they did not have a new line character in their format string. However, the following simple code is still not producing output for me:
#include <stdio.h>
int main() {
printf("Hello world!\n");
while (1);
return 0;
}
However, adding fflush(stdout); after the printf call produces output. The new line character is supposed to make this unnecessary, so why does it not work without it?
It's quite common for stdout to be line-buffered when connected to a terminal (flushed on line feed), and block-buffered otherwise (flushed when buffer is full).
For example,
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("foo\n");
sleep(5);
return 0;
}
Test:
$ ./a
foo
[5s pause]
$ ./a | cat
[5s pause]
foo
(gcc on Linux)
I'm using mingw with Eclipse on Windows.
It seems that Eclipse is connecting the stdout of your program to a pipe so it can collect the output and display it in its window. Your program thus uses block buffering for stdout.
A very good answer by #schot here.
He said :
The C99 standard does not specify if the three standard streams are unbuffered or line buffered: It is up to the implementation. All UNIX implementations I know have a line buffered stdin. On Linux, stdout is line buffered and stderr unbuffered.
One way to be sure that your line(s) will be printed directly is making stdout unbuffered:
setbuf(stdout, NULL);
/* or */
setvbuf(stdout, NULL, _IONBF, 0);
But you can only do this once, and it must be before you write to stdout or perform any other operantion on it. (C99 7.19.5.5 2)
Additional Info :
Shouldn't a new line character flush the output?
-It depends, if the output device is determined to be interactive (e.g. a terminal) the newline flush the buffer. Otherwise new line(s) don't flush the buffer.
What constitutes an interactive device is implementation-defined (C99 section 5.1.2.3/6) 

How to remove a character from a Linux terminal in C

How can I remove a character on the terminal before the cursor in Linux? In the past I used something like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define KEY_BACKSPACE 127
int main(){
printf("%s", "abc"); // add something so we can see if delete works
char * buf = malloc(3*sizeof(char));
*(buf+0)=KEY_BACKSPACE;
*(buf+1)=' ';
*(buf+2)=KEY_BACKSPACE;
write(1,buf,3);
free(buf);
}
This is only a small example demonstrating this technique. In the original program I disabled canonical mode and handled every keystroke myself. That's why I needed to remove characters.
Writing backspace, space, backspace worked fine in my original program. Now when I run same program after a few years, it didn't remove anything. What changed? What can I do to fix this?
As I noted in a comment, you need to use backspace instead of '\177' (or '\x7F') to move backwards. You also have to worry about buffering of standard I/O. It's often best not to use a mixture of standard I/O and file descriptor I/O on the same stream — standard output in this example. Use one or the other, but not both.
This works:
#include <unistd.h>
int main(void)
{
char buff1[] = "abc";
char buff2[] = "\b \b";
write(STDOUT_FILENO, buff1, sizeof(buff1) - 1);
sleep(2);
write(STDOUT_FILENO, buff2, sizeof(buff2) - 1);
sleep(2);
write(STDOUT_FILENO, "\n", 1);
return 0;
}
It shows first (for 2 seconds):
abc
then (for another 2 seconds):
ab
then it exits. The cursor is after c at first, then after b.
As explained by Jonathan Leffler in the comment, your code needs two modifications:
The rubout character understood by the typical terminal (emulator) is '\b' (or 8), not 127.
printf() is line-buffered by default when writing to a TTY. This means that you need to call fflush(stdout) between calls to printf() and write(). Without flushing abc will only be printed at program exit, so the deletion sequence will be emitted before the contents it is supposed to delete, which renders it inoperative.

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.

Resources