problem with fread/fwrite

Earl Chew cechew at bruce.cs.monash.OZ.AU
Tue Nov 13 11:56:01 AEST 1990


In <2677 at cirrusl.UUCP> dhesi%cirrusl at oliveb.ATC.olivetti.com (Rahul Dhesi) writes:

>In <13992 at ulysses.att.com> kpv at ulysses.att.com (Phong Vo[drew]) writes:

>   The standard, in this case, basically just documents the behavior of
>   stdio without considering that this is a bad design that arose from
>   a bad implementation. It is ugly to have to call fseek before
>   switching modes.

I think that this is true.

>I believe the requirement to call fseek (etc.) when switching arises
>out of the need to make stdio fast.  Due to buffering, alternating

This is not the case. The main obstacle to switching between reads and writes
is:

1. the behaviour of early implementations of stdio
2. subsequent casting of (1) in concrete by ANSI-C

There is a need to make stdio fast --- but this does not prohibit arbitrary
switching between read and write modes.

Most implementations of stdio buffer data between calls to read(2) and
write(2). Thus the cost of making a system call is only incurred every BUFSIZ
bytes. Intermediate data is transferred directly to the buffer.

The main impediment to switching modes in many implementations of stdio is the
use of a single buffer pointer (usually _ptr). This single pointer functions as
a read pointer when reading and a write pointer when writing, allowing quick
access to the buffer. Calls to a buffer fill or flush function are only made
when the pointer reaches some high water mark. Thus (getc(fp); putc(0, fp)) or
(putc(0, fp); getc(fp)), especially when the pointer is in the middle of the
buffer.

It is possible to perform an automatic mode switch if *two* pointers are used:
a reading pointer and a writing pointer.

>reads and writes can confuse each other.  The only way the stdio
>library could automatically protect you against this would be for it to
>explicitly test for internal state before every read and write.  E.g.,
>within fread, we sould have:

>     if (my_state == DOING_WRITE) {
>        .. resync buffer ..
>        my_state = DOING_READ;
>        .. rest of fread ..
>     }

Some implementations of stdio do this anyway to prevent users from hanging
themselves:

	if (my_state == DOING_WRITE) {
	  ... error ...
	}
	... rest of fread ...

In these cases, there already is a guard on the fread() code, so replacing
`... error ...' with `... resync buffer ...' is possible without loss in
performance for the normal case.

I am unsure whether ANSI-C prohibits stdio implementations from automatic
switching, but it clear that if such a feature were to be implemented, its use
would make the application non-conforming.

In any event, use of the separate read and write pointers allows runtime
checking to ensure that an explicit switch is made between read and write
modes, even if automatic switching is not implemented (ie it is possible to
trap {getc(fp); putc(0, fp);} or {putc(0, fp); getc(fp);}).

Earl
-- 
Earl Chew, Dept of Computer Science, Monash University, Australia 3168
EMAIL: cechew at bruce.cs.monash.edu.au PHONE: 03 5655447 FAX: 03 5655146
----------------------------------------------------------------------



More information about the Comp.lang.c mailing list