LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   C: printf() hangs linux pipes (http://www.linuxquestions.org/questions/programming-9/c-printf-hangs-linux-pipes-4175428396/)

romagnolo 09-21-2012 10:39 AM

C: printf() hangs linux pipes
 
I've written a simple I/O echoing program in C to test a problem with a bigger real program. Here, linux FD redirection doesn't work.
The echoing program (aka a.out) is:
Code:

#include <stdio.h>

int main(int argc, char **argv) {
  char buff[10];
  while (1) {
    if (fgets(buff, 10, stdin) == NULL) break;
    printf("PRINT: %s \n", buff);
  }
}


From Bash, I run it as:
Code:

$ mkfifo IN OUT
$ # this is a method to keep the pipes IN and OUT opened over time
$ while :; do read; echo Read: $REPLY >&2; sleep 1; done <OUT >IN &
$ a.out >OUT <IN &

$ echo xyz >IN

and there is no output produced: the Bash while loop isn't able to read from OUT.
Let's compare this a.out with cat, which instead works as expected:

Code:

$ mkfifo IN OUT
$ while :; do read; echo Read: $REPLY >&2; sleep 1; done <OUT >IN &
$ cat >OUT <IN &

$ echo xyz >IN
Read: xyz

This last line is printed on console to stderr. cat's output, differently from a.out's, is able to travel across OUT and reach the Bash while loop, which then prints it on console.
What's wrong with a.out?

dwhitney67 09-21-2012 11:09 AM

Quote:

Originally Posted by romagnolo (Post 4785917)
What's wrong with a.out?

It is your source code that has an issue.

Change your source code to the following (note the text in bold font), and it should function as expected:
Code:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
  char buff[10];
  while (1) {
    if (fgets(buff, sizeof(buff), stdin) == NULL) break;
    char* nl = strchr(buff, '\n');
    if (nl)
      *nl = '\0';

    printf("PRINT: %s \n", buff);
    fflush(stdout);
  }
  return 0;
}

To summarize: flush standard out, and to mimic 'cat', remove the newline that echo inserts into stream (or conversely, remove newline from printf).

firstfire 09-21-2012 11:09 AM

Hi.

Add
Code:

fflush(stdout);
after printf(). Look at `man fflush' or here for details.

romagnolo 09-21-2012 11:37 AM

Yes, fflush() solves the problem. So it seems stdin/out work differently if they run across an interactive console or a pipe. In fact, executing a.out directly with no redirections thru pipes produces immediate outputs to console and doesn't require fflush().

rknichols 09-21-2012 01:00 PM

Quote:

Originally Posted by romagnolo (Post 4785971)
Yes, fflush() solves the problem. So it seems stdin/out work differently if they run across an interactive console or a pipe.

It's nothing peculiar to stdout. Any stdio output stream is by default line buffered if output is going to a terminal and block buffered (typically 4KB blocks) otherwise. See the manpages for stdio(3) and setbuf(3).


All times are GMT -5. The time now is 11:59 AM.