0

There I was, almost sending a rage-mail to a subcontractor (again). They used printf(...) to report error instead of fprintf(stderr, ...), which I thought was dumb since stdout is (line) buffered. Especially when I found one of the prints in an assert-handler (probably ending in abort which does not flush open files).

Looking closer at the prints however, all of them ended with a newline. And since stdout is line buffered (by default), it got me thinking: is there any difference flush-wise?

Loufi
  • 1,215
  • 1
  • 8
  • 23
Andreas
  • 5,086
  • 3
  • 16
  • 36
  • 5
    Error messages should be reported on standard error so that they do not vanish down a pipeline and confuse following programs. So, independently of the flushing issues, it is simply wrong to report errors on standard output. – Jonathan Leffler Oct 10 '18 at 13:10
  • Using \n only matters if output is sent to the terminal. What you don't like. It makes no difference if it is redirected. isatty() decides what happens. – Hans Passant Oct 10 '18 at 13:25
  • [What are the rules of automatic flushing stdout buffer in C?](https://stackoverflow.com/q/39536212/2410359) is useful here. – chux - Reinstate Monica Oct 10 '18 at 13:55
  • Andreas: "stdout is line buffered (by default)" --> I have not found that C specifies this. Certainly that is implementation-defined behavior. – chux - Reinstate Monica Oct 10 '18 at 14:00

2 Answers2

1

Indeed, if a stream is line buffered and all output to it ends with a newline, then for the purposes of ensuring that output is not delayed and that you do not lose output on abnormal termination, being line buffered is just as good as being unbuffered. (A similar statement can be made if manual use of fflush is done consistently where needed.)

However, the statement you made and that you're relying on, that "stdout is line buffered (by default)", is false. Rather, except for stderr, all stdio files are line-buffered (or possibly unbuffered) by default only when connected to an interactive device (tty). Otherwise they are fully buffered.

Per 7.21.3 Files, ¶7 (emphasis mine):

At program startup, three text streams are predefined and need not be opened explicitly -- standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; 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 device.

and 7.21.5.3 The fopen function, ¶8:

When opened, a stream is fully buffered if and only if it can be determined not to refer to an interactive device. The error and end-of-file indicators for the stream are cleared.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Interesting assertion "all stdio files ...". Any support/cite for that? – chux - Reinstate Monica Oct 10 '18 at 13:53
  • @chux: Citations added. – R.. GitHub STOP HELPING ICE Oct 10 '18 at 16:18
  • Unclear how "line-buffered by default" comes in as the streams are either _unbuffered_, _fully buffered_ or _line buffered_. The interactive device condition sets aside _fully buffered_, leaving _unbuffered_ or _line buffered_. Perhaps there is something more to insure `stdout` as _line-buffered_? – chux - Reinstate Monica Oct 10 '18 at 16:27
  • @chux: Indeed the standard allows them to be unbuffered in that case too, but no implementors choose to do that because it's awful and no better than line-buffered for practical purposes. I've made a small edit to note that. – R.. GitHub STOP HELPING ICE Oct 10 '18 at 16:39
  • Note that this is a pretty weak requirement -- "if and only if the stream **can be determined** not to refer to an interactive device". What if it can't easily be determined whether or not stdout refers to an interactive device? How much effort does the standard require, or can an implementation simply say "I can't determine" and set it to unbuffered or line buffered regardless and still claim conformance? – Chris Dodd Oct 10 '18 at 16:59
  • 1
    I'm also not sure how many implementation really follow this -- on Linux, if stdout refers (directly) to a network socket it will be fully buffered even if that network socket is remotely connected to an interactive device. If it's connected to a pty (pseudo-terminal) it will be line buffered even if that pty is not connected to an interactive device. I guess the standard never defines what "an interactive device" is, so that leaves a lot of wiggle room. – Chris Dodd Oct 10 '18 at 17:03
  • 1
    @ChrisDodd: A socket is not an interactive device. The standard leaves it implementation-defined, but for POSIX and practical real-world purposes "interactive device" means a tty. Regarding "can be determined", an implementation could decide that it can never determine and then always use unbuffered or line buffered mode by default, but it would not be safe to assume an implementation does this, and one which does would have abysmal performance characteristics, e.g. in a loop doing `putc('\n',f)`. – R.. GitHub STOP HELPING ICE Oct 10 '18 at 17:23
  • @R.. *the standard leaves it implementation-defined* Indeed. [**5.1.2.3 Program execution**, paragraph 7](https://port70.net/~nsz/c/c11/n1570.html#5.1.2.3p7): "What constitutes an interactive device is implementation-defined." The [POSIX definition for a "terminal"](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html#tag_11) doesn't seem to preclude much, however, other than seemingly and implicitly stating (at least to me) that `isatty()` *de facto* defines an "interactive device". – Andrew Henle Oct 10 '18 at 20:00
0

Is there a difference between line buffered and unbuffered file when write end with newline?

is there any difference flush-wise?

Given a flush is "any unwritten buffer contents are transmitted to the host environment" C11dr §7.21.3 4

If all stdout output ends with a '\n' and that stream is unbuffered or line buffered, then a following flush is not expected to do anything as there is no unwritten data.

The C spec is a bit loose here. The detailed behavior is implementation defined. Best to use fflush(stdout); to insure output is flushed by that time. More info.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • *Best to use fflush(stdout); to insure output is flushed by that time.* I's say if you're emitting an error message, emit it to `stderr` and then flush it. – Andrew Henle Oct 10 '18 at 19:47
  • @AndrewHenle Yes agree with [Jonathan Leffler](https://stackoverflow.com/questions/52740580/is-there-a-difference-between-line-buffered-and-unbuffered-file-when-write-end-w/52745172?noredirect=1#comment92406762_52740580). Even with errors out `stderr`, a prior `fflush(stdout)` may help to insure the order of output with co-mingled output. Yet when its time for an error message, sometimes best to avoid extraneous other actively. – chux - Reinstate Monica Oct 10 '18 at 23:02