From the C11 standard, fseek
has a similar limitation:
For a text stream, either offset
shall be zero, or offset
shall be a value returned by an earlier successful call to the ftell
function on a stream associated with the same file and whence
shall be SEEK_SET
The reason is that text streams don't have a one-to-one mapping between the actual bytes of the source and the bytes you would get from fgetc
; e.g. on windows systems, the newline character in C tends to be translated into a sequence of two binary characters: carriage return, then line feed.
Consequently, the notion of arbitrarily positioning a text stream based on a numerical index is fraught with complications and surprises.
In fact, the documentation of ftell
warns
For a text stream, its file position indicator contains unspecified information, usable by the fseek
function for returning the file position indicator for the stream to its position at the time of the ftell
call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
Binary streams don't have this limitation, although
A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END
The above assumes you are working with byte-oriented streams. Wide-oriented streams have additional restrictions. e.g. under Streams
:
Binary wide-oriented streams have the file-positioning restrictions ascribed to both text and binary streams
and
For wide-oriented streams, after a successful call to a file-positioning function that leaves the file position indicator prior to the end-of-file, a wide character output function can overwrite a partial multibyte character; any file contents beyond the byte(s) written are henceforth indeterminate
fsetpos
does more than just set the file position: again from the C11 standard:
The fsetpos
function sets the mbstate_t
object (if any) and file position indicator
which makes it more suitable for setting the position in a wide-oriented streams.