Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #53855 > unrolled thread

fseek(), offset and ftell()

Started byarnuld <sunrise@invalid.address>
First post2014-12-04 08:42 +0000
Last post2014-12-04 21:29 -0500
Articles 10 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  fseek(), offset and ftell() arnuld <sunrise@invalid.address> - 2014-12-04 08:42 +0000
    Re: fseek(), offset and ftell() Robert Wessel <robertwessel2@yahoo.com> - 2014-12-04 03:28 -0600
    Re: fseek(), offset and ftell() James Kuyper <jameskuyper@verizon.net> - 2014-12-04 11:25 -0500
      Re: fseek(), offset and ftell() glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-12-04 16:49 +0000
    Re: fseek(), offset and ftell() Keith Thompson <kst-u@mib.org> - 2014-12-04 09:05 -0800
      Re: fseek(), offset and ftell() "Bill Cunningham" <nospam@nspam.invalid> - 2014-12-04 14:13 -0500
        Re: fseek(), offset and ftell() "Bill Cunningham" <nospam@nspam.invalid> - 2014-12-04 16:01 -0500
      Re: fseek(), offset and ftell() glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-12-04 21:42 +0000
        Re: fseek(), offset and ftell() Nobody <nobody@nowhere.invalid> - 2014-12-05 00:24 +0000
          Re: fseek(), offset and ftell() "Bill Cunningham" <nospam@nspam.invalid> - 2014-12-04 21:29 -0500

#53855 — fseek(), offset and ftell()

Fromarnuld <sunrise@invalid.address>
Date2014-12-04 08:42 +0000
Subjectfseek(), offset and ftell()
Message-ID<54801e7e$0$297$14726298@news.sunsite.dk>
There are several contradicting definitions of the behavior of fseek() . 
I do not know mhich one to believe:

> n1570.pdf: 
> section 7.21.9.2 

> int fseek(FILE *stream, long int offset, int whence);

> For a binary stream, the new position, measured in characters from the 
> beginning of the file, is obtained by adding offset to the position 
> specified by whence. The specified position is the beginning of the 
> file if whence is SEEK_SET, the current value of the file position 
> indicator if SEEK_CUR, or end-of-file if SEEK_END. A binary stream need
> not meaningfully support fseek calls with a whence value of SEEK_END.

I have used seek on a text file (I assume a file containing C code as 
text qualifies as a text stream) and I see new position is measured in 
characters there too. Then why standard mentioned only binary streams ?
 

> 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.

Standard says value should be eitehr zero or a returned value from
ftell() which returns only current position.  Now if I want to go past 
the 100 characters and start reading from 101st character onwards, how to 
do that ?  In gcc simply putting 100 or 101 or 9 works, you can seek to 
any character by just putting it as 2nd argument to fseek() but is that 
correct way ? 


-- 
arnuld
http://lispmachine.wordpress.com/

[toc] | [next] | [standalone]


#53856

FromRobert Wessel <robertwessel2@yahoo.com>
Date2014-12-04 03:28 -0600
Message-ID<ro908atorhi7n1199ohngm04l2j76m54sc@4ax.com>
In reply to#53855
On 04 Dec 2014 08:42:39 GMT, arnuld <sunrise@invalid.address> wrote:

>There are several contradicting definitions of the behavior of fseek() . 
>I do not know mhich one to believe:
>
>> n1570.pdf: 
>> section 7.21.9.2 
>
>> int fseek(FILE *stream, long int offset, int whence);
>
>> For a binary stream, the new position, measured in characters from the 
>> beginning of the file, is obtained by adding offset to the position 
>> specified by whence. The specified position is the beginning of the 
>> file if whence is SEEK_SET, the current value of the file position 
>> indicator if SEEK_CUR, or end-of-file if SEEK_END. A binary stream need
>> not meaningfully support fseek calls with a whence value of SEEK_END.
>
>I have used seek on a text file (I assume a file containing C code as 
>text qualifies as a text stream) and I see new position is measured in 
>characters there too. Then why standard mentioned only binary streams ?
> 
>
>> 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.
>
>Standard says value should be eitehr zero or a returned value from
>ftell() which returns only current position.  Now if I want to go past 
>the 100 characters and start reading from 101st character onwards, how to 
>do that ?  In gcc simply putting 100 or 101 or 9 works, you can seek to 
>any character by just putting it as 2nd argument to fseek() but is that 
>correct way ? 


There simply is no standard way to do that on a text stream.  Consider
a platform like Windows that store two bytes in the text file for a
\n.  Remember that your C program will always see the \n as a *single*
character, despite the fact that (on Windows) it's store as two bytes.
There's no good way to seek some number of characters without reading
each intervening character to check for cf/lf pairs.

OTOH, you can read forward yourself.

Or use a binary stream, but then you have to deal with line ends
yourself.

On some platforms seeking on a text file works exactly as you'd hope,
for example on most *nix implementations, but it's definitely not
standard, and may or may not by something your implementation promises
(whether or not it works at the moment).

[toc] | [prev] | [next] | [standalone]


#53892

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-12-04 11:25 -0500
Message-ID<54808AF8.8090603@verizon.net>
In reply to#53855
On 12/04/2014 03:42 AM, arnuld wrote:
> There are several contradicting definitions of the behavior of fseek() .

What are the contradictory definitions? Unless I've misread your
message, you only provide one definition below, and I didn't notice any
internal contradictions. What contradictions have you seen between the
definitions you're referring to?

> I do not know mhich one to believe:
> 
>> n1570.pdf: 
>> section 7.21.9.2 
> 
>> int fseek(FILE *stream, long int offset, int whence);
> 
>> For a binary stream, the new position, measured in characters from the 
>> beginning of the file, is obtained by adding offset to the position 
>> specified by whence. The specified position is the beginning of the 
>> file if whence is SEEK_SET, the current value of the file position 
>> indicator if SEEK_CUR, or end-of-file if SEEK_END. A binary stream need
>> not meaningfully support fseek calls with a whence value of SEEK_END.
> 
> I have used seek on a text file (I assume a file containing C code as 
> text qualifies as a text stream) and I see new position is measured in 
> characters there too. Then why standard mentioned only binary streams ?

Because there are many different ways a text stream can indicate the end
of a line, and correspondingly many different ways of implementing
fseek() on text streams. Examples of schemes that I've heard about:
1. A single new-line character - which can be different on different
systems.
2. A pair of characters that together indicate end-of-line - the pairing
can be different on different systems.
3. Files organized in blocks, with end-of-line within a block indicated
by having the rest of the block filled in with padding. On some systems,
the padding character is '\0', but on others it's a blank - which is why
the standard explicitly permits the number of blank characters at the
end of a line be different when it is read from a text stream than it
was when the line was written.
4. Files organized in blocks, with end-of-line indicated by a byte at
the beginning of the block saying how much of the block is actually
used. The remaining bytes of the block might be either padded or filled
with garbage.

So - how would you like the offset to work when it crosses the end of a
line? Should it increase by only 1, regardless of how end-of-line is
indicated? Should it increase by 2 if the two characters are used to
indicate end-of-line? Should it include or exclude padding/garbage at
the end of a block? Each way of doing things has it's advantages and
disadvantages, and different systems make different choices. The
committee chose to define text mode for the specific purpose of allowing
such variations. If such variations weren't allowed, binary mode would
not need to be distinct from text mode.

>> 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.
> 
> Standard says value should be eitehr zero or a returned value from
> ftell() which returns only current position.  Now if I want to go past 
> the 100 characters and start reading from 101st character onwards, how to 
> do that ?  In gcc simply putting 100 or 101 or 9 works, you can seek to 
> any character by just putting it as 2nd argument to fseek() but is that 
> correct way ?

Violating a "shall" that occurs outside of a constraint section means
that the behavior is undefined - which is standardese with simply means
that the standard itself does not define the behavior - the
implementation is free to provide it's own definition. On Unix-like
systems, text mode behaves exactly the same as binary mode, so what
you're saying should work fine. You'll have to read the documentation
for other systems to find out what works there. Since the behavior is
undefined, rather than implementation-defined, a conforming
implementation of C need not provide such documentation, but any
reasonable implementation of C will document it.

For portable code working on a text stream, replace calls to fseek()
which would violate those shalls with calls to functions which read the
the appropriate number of characters, which you can then discard
unprocessed. This will result in newlines always being treated as 1
character long, regardless of the actual method used to indicate
end-of-line.

[toc] | [prev] | [next] | [standalone]


#53894

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-12-04 16:49 +0000
Message-ID<m5q39s$u4a$1@speranza.aioe.org>
In reply to#53892
James Kuyper <jameskuyper@verizon.net> wrote:
> On 12/04/2014 03:42 AM, arnuld wrote:
>> There are several contradicting definitions of the behavior of fseek() .
 
(snip)

> Because there are many different ways a text stream can indicate the end
> of a line, and correspondingly many different ways of implementing
> fseek() on text streams. Examples of schemes that I've heard about:

(snip)

> 4. Files organized in blocks, with end-of-line indicated by a byte at
> the beginning of the block saying how much of the block is actually
> used. The remaining bytes of the block might be either padded or filled
> with garbage.

For VM/CMS, the system keeps track of block numbers, but not the
length of blocks. For fixed length blocks, in non-text files, it
can figure out the byte offset. Otherwise, ftell() returns, and
fseek() accepts 32768*block+offset. 

I believe for FB the trailing blanks are returned as part of the
data, but it could be that they are removed. 

The VB format has a four byte block descriptor at the beginning
of a block, and a four byte record descriptor at the beginning
of each record. For text files, you get '\n' as usual. 
 
> So - how would you like the offset to work when it crosses the end of a
> line? Should it increase by only 1, regardless of how end-of-line is
> indicated? Should it increase by 2 if the two characters are used to
> indicate end-of-line? Should it include or exclude padding/garbage at
> the end of a block? Each way of doing things has it's advantages and
> disadvantages, and different systems make different choices. The
> committee chose to define text mode for the specific purpose of allowing
> such variations. If such variations weren't allowed, binary mode would
> not need to be distinct from text mode.

(snip)

-- glen

[toc] | [prev] | [next] | [standalone]


#53896

FromKeith Thompson <kst-u@mib.org>
Date2014-12-04 09:05 -0800
Message-ID<lna933pcqk.fsf@nuthaus.mib.org>
In reply to#53855
arnuld <sunrise@invalid.address> writes:
> There are several contradicting definitions of the behavior of fseek() . 
> I do not know mhich one to believe:

There is no real contradiction.

>> n1570.pdf: 
>> section 7.21.9.2 
>
>> int fseek(FILE *stream, long int offset, int whence);
>
>> For a binary stream, the new position, measured in characters from the 
>> beginning of the file, is obtained by adding offset to the position 
>> specified by whence. The specified position is the beginning of the 
>> file if whence is SEEK_SET, the current value of the file position 
>> indicator if SEEK_CUR, or end-of-file if SEEK_END. A binary stream need
>> not meaningfully support fseek calls with a whence value of SEEK_END.
>
> I have used seek on a text file (I assume a file containing C code as 
> text qualifies as a text stream) and I see new position is measured in 
> characters there too. Then why standard mentioned only binary streams ?
>
>> 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.
>
> Standard says value should be eitehr zero or a returned value from
> ftell() which returns only current position.  Now if I want to go past 
> the 100 characters and start reading from 101st character onwards, how to 
> do that ?  In gcc simply putting 100 or 101 or 9 works, you can seek to 
> any character by just putting it as 2nd argument to fseek() but is that 
> correct way ? 

On a UNIX-like system, a text file is a sequence of lines, where each
line is a sequence of characters terminated by a '\n' character.  You
can read the same file in text or binary mode and get exactly the same
byte sequence.

That's not true on all systems, and the standard doesn't require it.

The standard only specifies the behavior that's guaranteed for *all*
conforming implementations.

    A binary stream need not meaningfully support fseek calls with a
    whence value of SEEK_END.

Some systems might store binary files as a whole number of fixed-length
blocks, with no information about how many bytes are in the final block.
On such a system, fseek with SEEK_END might go to the end of the last
block, even if not that many bytes have been written.  On a UNIX-like
system, a binary file is stored as an arbitrary sequence of bytes, and
fseek with SEEK_END works perfectly well.  Code that relies on this will
not be portable to non-UNIX systems.

    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.

This is a Standardese use of the word "shall".  If the word "shall"
appears in the Standard outside a constraint, as it does here, it
doesn't mean that something is either required or forbidden; it means
that any program that violates it has undefined behavior (which merely
means behavior that is not defined *by the C standard*).

If you fseek() to position 100 in a text file on a UNIX-file system, it
will do exactly what you expect.  The above quoted paragraph merely
means that the C standard doesn't guarantee that behavior.

Some examples:

On Windows, end-of-line is represented by a 2-character sequence "\r\n".
Reading an end-of-line from a text file on Windows returns a single '\n'
character, but fseek works on the number of bytes *in the physical
file*, not the number of characters you'll get if you read from it.  You
can specify a position in a text file by reading to that position and
then calling ftell(); that method will work on any conforming C
implementation.

On other systems, text files might be stored as fixed-length records.
Reading from such a file in text mode will convert that format to
sequences of characters terminated by '\n'; seeking to arbitary
positions won't do what you expect, and might not even be permitted.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#53900

From"Bill Cunningham" <nospam@nspam.invalid>
Date2014-12-04 14:13 -0500
Message-ID<m5qbns$l1u$1@speranza.aioe.org>
In reply to#53896
"Keith Thompson" <kst-u@mib.org> wrote in message 
news:lna933pcqk.fsf@nuthaus.mib.org...

> On a UNIX-like system, a text file is a sequence of >lines, where each
> line is a sequence of characters terminated by a '\n' >character.  You
> can read the same file in text or binary mode and get >exactly the same
> byte sequence.
>
> That's not true on all systems, and the standard doesn't >require it.
>
> The standard only specifies the behavior that's >guaranteed for *all*
> conforming implementations.
>
>    A binary stream need not meaningfully support fseek >calls with a
>    whence value of SEEK_END.

    I'm glad you mentioned this Keith. I will also mention fget_pos and 
fput_pos, but I don't think they need any introduction.
    On my linux there is a unix2dos and dos2unix command, respectively. DOS 
has control line terminators as windows and DOS use that. Linux and *nixes. 
Indeed do not.

Bill

[toc] | [prev] | [next] | [standalone]


#53904

From"Bill Cunningham" <nospam@nspam.invalid>
Date2014-12-04 16:01 -0500
Message-ID<m5qi3t$5pj$1@speranza.aioe.org>
In reply to#53900
"Bill Cunningham" <nospam@nspam.invalid> wrote in message 
news:m5qbns$l1u$1@speranza.aioe.org...
>
> "Keith Thompson" <kst-u@mib.org> wrote in message 
> news:lna933pcqk.fsf@nuthaus.mib.org...
>
>> On a UNIX-like system, a text file is a sequence of >lines, where each
>> line is a sequence of characters terminated by a '\n' >character.  You
>> can read the same file in text or binary mode and get >exactly the same
>> byte sequence.
>>
>> That's not true on all systems, and the standard doesn't >require it.
>>
>> The standard only specifies the behavior that's >guaranteed for *all*
>> conforming implementations.
>>
>>    A binary stream need not meaningfully support fseek >calls with a
>>    whence value of SEEK_END.
>
>    I'm glad you mentioned this Keith. I will also mention fget_pos and 
> fput_pos, but I don't think they need any introduction.
>    On my linux there is a unix2dos and dos2unix command, respectively. DOS 
> has control line terminators as windows and DOS use that. Linux and 
> *nixes. Indeed do not.
>
> Bill

    Correction fgetpos and fsetpos.

[toc] | [prev] | [next] | [standalone]


#53906

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-12-04 21:42 +0000
Message-ID<m5qkfg$ck8$1@speranza.aioe.org>
In reply to#53896
Keith Thompson <kst-u@mib.org> wrote:
> arnuld <sunrise@invalid.address> writes:
>> There are several contradicting definitions of the behavior of fseek() . 

(snip)
>> Standard says value should be eitehr zero or a returned value from
>> ftell() which returns only current position.  Now if I want to go past 
>> the 100 characters and start reading from 101st character onwards, how to 
>> do that ?  In gcc simply putting 100 or 101 or 9 works, you can seek to 
>> any character by just putting it as 2nd argument to fseek() but is that 
>> correct way ? 
 
> On a UNIX-like system, a text file is a sequence of lines, where each
> line is a sequence of characters terminated by a '\n' character.  You
> can read the same file in text or binary mode and get exactly the same
> byte sequence.
 
> That's not true on all systems, and the standard doesn't require it.
 
> The standard only specifies the behavior that's guaranteed for *all*
> conforming implementations.
 
>    A binary stream need not meaningfully support fseek calls with a
>    whence value of SEEK_END.
 
> Some systems might store binary files as a whole number of fixed-length
> blocks, with no information about how many bytes are in the final block.
> On such a system, fseek with SEEK_END might go to the end of the last
> block, even if not that many bytes have been written.  On a UNIX-like
> system, a binary file is stored as an arbitrary sequence of bytes, and
> fseek with SEEK_END works perfectly well.  Code that relies on this will
> not be portable to non-UNIX systems.

As I understand the way PDF readers are supposed to work, they fseek()
to the end, back up some, and look for a special byte sequence.
If the block padding isn't so big, it should be able to find what
it needs. 

When that fails, I believe that Adobe Reader instead starts reading
from the beginning. 

Presumably those who compile versions of Adobe Reader know the
fseek() properties of the system in use.
 
>    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.
 
> This is a Standardese use of the word "shall".  If the word "shall"
> appears in the Standard outside a constraint, as it does here, it
> doesn't mean that something is either required or forbidden; it means
> that any program that violates it has undefined behavior (which merely
> means behavior that is not defined *by the C standard*).
 
> If you fseek() to position 100 in a text file on a UNIX-file system, it
> will do exactly what you expect.  The above quoted paragraph merely
> means that the C standard doesn't guarantee that behavior.
 
> Some examples:
 
> On Windows, end-of-line is represented by a 2-character sequence "\r\n".
> Reading an end-of-line from a text file on Windows returns a single '\n'
> character, but fseek works on the number of bytes *in the physical
> file*, not the number of characters you'll get if you read from it.  You
> can specify a position in a text file by reading to that position and
> then calling ftell(); that method will work on any conforming C
> implementation.

I mentioned before how VM/CMS does it for some file types. CMS
keeps track of block numbers, but not the length of the blocks.
Users can choose a block size between 1 and about 32767 bytes.
(It can't be less than 9 for variable length records.)
 
> On other systems, text files might be stored as fixed-length records.
> Reading from such a file in text mode will convert that format to
> sequences of characters terminated by '\n'; seeking to arbitary
> positions won't do what you expect, and might not even be permitted.

For fixed length records, (and blocks) CMS fseek can convert a byte 
offset to a block number and block offset for both text and non-text.

I believe for VB, both text and non-text, it uses 32768*block+offset.

If a program reads from the beginning, recording the values of
ftell() all the way through, it will work as expected. 

-- glen

[toc] | [prev] | [next] | [standalone]


#53908

FromNobody <nobody@nowhere.invalid>
Date2014-12-05 00:24 +0000
Message-ID<pan.2014.12.05.00.24.03.504000@nowhere.invalid>
In reply to#53906
On Thu, 04 Dec 2014 21:42:08 +0000, glen herrmannsfeldt wrote:

> Presumably those who compile versions of Adobe Reader know the
> fseek() properties of the system in use.

Examining the dependencies of AcroRd32.exe indicates that it doesn't
use MSVCRT (the library providing the standard C library functions),
but instead uses the Windows I/O functions (SetFilePointer() is the
equivalent of fseek()).

Which isn't particularly surprising. C's stdio functions are something of
a lowest common denominator. The OS' native I/O capabilities will always
offer additional functionality. Probably the most common issue with
stdio is that fseek/ftell are problematic for files whose size cannot fit
into a signed "long" (which is only 32 bits even on "64-bit" versions of
Windows).

[toc] | [prev] | [next] | [standalone]


#53914

From"Bill Cunningham" <nospam@nspam.invalid>
Date2014-12-04 21:29 -0500
Message-ID<m5r5a0$fp2$1@speranza.aioe.org>
In reply to#53908
"Nobody" <nobody@nowhere.invalid> wrote in message 
news:pan.2014.12.05.00.24.03.504000@nowhere.invalid...

[...]

Probably the most common issue with
> stdio is that fseek/ftell are problematic for files whose size cannot fit
> into a signed "long" (which is only 32 bits even on "64-bit" versions of
> Windows).

    I noticed that myself lately.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web