Why can't an output be followed by an input and vice versa?

Viewed 206

From APUE

When a file is opened for reading and writing (the plus sign in the type), two restrictions apply.

• Output cannot be directly followed by input without an intervening fflush, fseek, fsetpos, or rewind.

• Input cannot be directly followed by output without an intervening fseek, fsetpos, or rewind, or an input operation that encounters an end of file.

Why "fseek, fsetpos, or rewind" in both cases?

Why "an input operation that encounters an end of file" in the second case?

Thanks.

A similar question for Linux API is Can `read()` be directly followed by `write()` and `write()` by `read()`?

2 Answers

When working with a FILE stream, there is a single internal buffer used when either reading from or writing to the file.

When switching between reading and writing, that buffer must be cleared before switching modes, otherwise data loss could potentially occur. Each of the operations mentioned above perform the required flushing of the buffer.

the C standard doesn't say file positioning functions internally flush output to device or clear input cache.

The Standard indeed hasn't mentioned about the detail of somewhat internal buffering mechanism, because it varies from OS to OS; that is, implementation dependent. Thus, the standard is not responsible for defining it.

I was wondering why the file positioning functions (if not fflush) should be called between output and input?

Since the behaviour is implementation dependent, for some OS (e.g. Ubuntu), interestingly, there is no need for us to call fflush(),fseek() explicitly, while others(e.g. macOS) strictly needs.

For the sake of a concrete description, I've run some tests on two OS:

  1. macOS Big Sur (Darwin Kernel Version 20.6.0)
  2. Ubuntu 14 (GNU/Linux 4.4.0-142-generic)

Taking an example of "replace the 5th character in the file", and assume that the file content is

1234_6789

and the program is as followes:

show_file_content();

getc(fp);
getc(fp);
getc(fp);
getc(fp);

/* this line is indispensable for macos, but NOT for ubuntu */
fseek(fp,0,SEEK_CUR);

putc('5', fp);

printf("->");

show_file_content();

the above program's output is (no matter running on macOS or Ubuntu):

1234_6789->123456789

But, if we comment the line of fseek, things are different; the outputs are... macOS:

1234_6789->1234_67895

Ubuntu:

1234_6789->123456789

You can try this test on other different OSes. The comparison between two different Unix-based OSes suffices to understand the APUE's statement.

Related