1

I countered something that really irritate me while running this code on https://cpp.sh/

// taken from here https://cplusplus.com/reference/cstdlib/atoi/
#include <stdio.h>      /* printf, fgets */
#include <stdlib.h>     /* atoi */

int main ()
{
  //* setbuf(stdout, NULL);
  int i;
  char buffer[256];
  printf ("Enter a number: ");
  fgets (buffer, 256, stdin);
  i = atoi (buffer);
  printf ("The value entered is %d. Its double is %d.\n",i,i*2);
  return 0;
}

it shows the next output (entered "10\n" as input):

10 
Enter a number: The value entered is 10. Its double is 20.

I am familiar with the concept of linux pipes and buffering, and I know that the pip flush the content of stdout before listening to input, so I wonderd why fgets don't flush stdout before waiting to input.

when removing the comment from the line with * it works as expected, and while compile and run with gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 also works, so I don't understand whats going on when I run it on the online c++ compiler?

  • 1
    What does any of this have to do with pipes? – Barmar Apr 27 '23 at 20:53
  • because it works when I set the stdout to be unbuffers, and the buffers sit in the pipe. am I wrong? – nadav levin Apr 27 '23 at 20:54
  • 1
    I do not understand. Why would you expect `fgets(... stdin)` to do _anything_ with `stdout`? There is however a "special case" in glibc https://github.com/bminor/glibc/blob/af16a59ee1f72392b88d439d8f802c9844f86f4f/libio/fileops.c#L491 , but I do not know if it is relevant. – KamilCuk Apr 27 '23 at 20:57
  • No, the buffer is in stdio. – Barmar Apr 27 '23 at 20:58
  • If this were the pipe's buffer, how would `setbuf()` change it? That just controls stdio buffering. – Barmar Apr 27 '23 at 20:59
  • but setbuf getting a stream as parameter so why it can't interfere with stdout buffering? – nadav levin Apr 27 '23 at 21:09
  • @KamilCuk according to [online c 2011 standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 7.21.3 Files When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment – nadav levin Apr 27 '23 at 21:12
  • 1
    stdin and stdout are different streams. One is stdin, the other is stdout. – KamilCuk Apr 27 '23 at 21:18
  • It's not clear to me what you mean by "and I know that the pip flush the content of stdout before listening to input". Do you mean that you believe that the call to `fgets` will flush stdout? That's simply not true. If you want to flush stdout, you should call `fflush(stdout);` – William Pursell Apr 27 '23 at 21:23
  • why not? [couldn't find something more formal fast his assumptions are wrong?](https://stackoverflow.com/questions/39536212/what-are-the-rules-of-automatic-stdout-buffer-flushing-in-c) – nadav levin Apr 27 '23 at 21:27

1 Answers1

2

By default, stdout is fully buffered unless it's connected to a terminal; in that case it's line-buffered. The prompt won't be printed until the output buffer fills up, which is likely to be 4K bytes.

You can call fflush(stdout) to force the buffer to be written to the pipe.

  printf ("Enter a number: ");
  fflush(stdout);
  fgets (buffer, sizeof buffer, stdin);
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • interesting but I don't understand why the stdout stream open as fully buffered to begin with, according to [this](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) "the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive devic" – nadav levin Apr 27 '23 at 21:21
  • I think the `cpp.sh` website is using a pipe, not a terminal. – Barmar Apr 27 '23 at 21:30
  • make sense thanks, if you could also reflect about my understanding in buffering because I started to be confused, each file descriptor have its own buffer and I can create a pipe from one file descriptor to another that will contain 16 buffers that will act like one? and it lays in kernel mode right, if I am not in the right path I would love to get any sources to wrap my head around it – nadav levin Apr 27 '23 at 21:39
  • There are lots of different buffers at different levels. The buffers you're concerned with are in `FILE` objects managed by stdio, not file descriptors or pipes. – Barmar Apr 27 '23 at 21:41
  • 1
    @nadavlevin: pipes are not interactive devices, so when stdout is associated with a pipe, it will be fully buffered. On linux (and unix systems in general), "interactive device" and "terminal" mean the same thing. – Chris Dodd Apr 27 '23 at 22:13