44

What's the difference between using the functions fgetpos() and fsetpos() and using the functions ftell() and fseek() to get and set a position in a file?

What are fgetpos() and fsetpos() good for? Why would they be used instead of ftell() and fseek()?

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
carlfilips
  • 2,574
  • 3
  • 21
  • 27
  • 1
    See http://stackoverflow.com/questions/12119132/ftello-fseeko-vs-fgetpos-fsetpos It's answer is way better than the accepted answer here. – Mecki Jun 24 '15 at 23:39

4 Answers4

29

None of the above answers are correct - in fact if you use fsetpos interchangeably with fseek you could introduce a security flaw (https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=20087255).

The reason is that the fpos_t *pos argument to fsetpos isn't actually an integer so it can't be used to seek to arbitrary locations in a file. The only valid values are therefore ones obtained from fgetpos. As the docs say,

The internal file position indicator associated with stream is set to the position represented by pos, which is a pointer to an fpos_t object whose value shall have been previously obtained by a call to fgetpos.

(http://www.cplusplus.com/reference/cstdio/fsetpos/)

If all you want is the ability to seek to arbitrary locations beyond 32-bit boundary, then use ftello / fseeko and compile with #define _FILE_OFFSET_BITS 64.

HughHughTeotl
  • 5,439
  • 3
  • 34
  • 49
  • 1
    Not actually exact answer for the question, but very good as tip! Thanks! – likern Feb 17 '14 at 02:36
  • 1
    @likern This is exactly the answer to the question. And it's also the correct answer, the accepted answer is absolutely incorrect, as `fpos_t` may not be an integer at all (the standard doesn't require it to be). – Mecki Jun 24 '15 at 23:36
  • `ftello` and `fseeko` are POSIX functions. Moreover the C11 Standard states in 7.21.9.1:"The fgetpos function stores the current values of the parse state (if any) and file position indicator for the stream pointed to by stream in the object pointed to by pos" Furthermore: in 7.21.1 it is stated:"`fpos_t` which is a complete object type other than an array type capable of recording all the information needed to specify uniquely every position within a file" However, at least on my system `fpos_t` is a `__darwin_off_t` which turns out to be a `__int64_t`. Use fsetpos and fgetpos when possibl – math May 03 '16 at 08:37
  • 1
    I cannot open the link :/ Any copy of the reasoning? – Flamefire Dec 02 '19 at 14:28
  • I won't say this is wrong, because I don't know, but every time I have taken advice from Confluence on potential C security risks they have been wrong. – Hunter Kohler Aug 10 '21 at 16:24
18

Well, from the manpage we can see that ftell and fseek use type long int to represent offsets (positions) in a file, and may therefore be limited to offsets which can be represented in a long int. (Type long int is not guaranteed to hold values larger than 2**31-1, limiting the maximum offset to 2 gigabytes). The newer fgetpos and fsetpos functions, on the other hand, use a special typedef, fpos_t, to represent the offsets. The type behind this typedef, if chosen appropriately, can represent arbitrarily large offsets, so fgetpos and fsetpos can be used with arbitrarily huge files. fgetpos and fsetpos also record the state associated with multibyte streams.

carlfilips
  • 2,574
  • 3
  • 21
  • 27
  • 9
    **This answer is incorrect!** If you just want to seek beyond `2**31-1` then there's `fseeko`. The correct answer is that `fgetpos` can only seek to a position previously obtained by `fgetpos` and that `fpos_t` **must not** be interpreted as an integer at all, as the man page says: *On some non-UNIX systems, **an fpos_t object may be a complex object** and these routines may be the only way to portably reposition a text stream.* – Mecki Jun 24 '15 at 23:33
  • @Mecki Yes indeed, this answer is wrong. As far as I understand my answer below is the only correct one. – HughHughTeotl Jun 26 '15 at 07:24
  • 5
    No the answer is not incorrect but insufficient. It correctly states the limits of `fseek` and friends, and it correctly says that `fgetpos` and friends are an option not having such limits. The answer above never states that you can mix `fseek` and `fsetpos` and firends, which is indeed dangerous. Further, it never states that `fpos_t` is an integral type. Instead Mecki suggests `fseeko` and firends which are non-ISO-C-standard functions (but POSIX functions). – math May 03 '16 at 08:46
6

fgetpos() goes with fsetpos(). And ftell() goes with fseek().

fgetpos() looks practically like ftell() because both take a FILE* parameter, and both return some kind of position in the file, albeit with a slightly different style. But get this: ONLY fseek() allows you to seek from the beginning of the file, from your current position in the file, and backwards from the end of the file (the third argument to fseek() being SEEK_SET, SEEK_CUR, and SEEK_END). fsetpos() doesn't do this. fsetpos() is limited to going back to some position you got from fgetpos().

Let us say you want to read a file into memory. How much heap do you need from malloc()? You need the size of the file. And I have yet to find any function in the C Standard Library that will tell you the size of a file, though some C Compilers may add a non-standard function. For example, Borland Turbo C had filelength(). But I have not seen filelength() amongst the STANDARD C Library.

So, what you can do is use fseek() to 0 bytes before the END of the file. Then use ftell() to get the position in bytes, and base your calculation for amount of heap memory on that.

What else could you do to get the file size? You could use fgetc() to read each character, counting until you get to the end. But I think using fseek() and ftell() is better and easier.

Indinfer
  • 532
  • 5
  • 4
-3

There is no difference in the functionally, although the interfaces are defined differently. They both are implemented because both are part of POSIX.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
m1tk4
  • 3,439
  • 1
  • 22
  • 27
  • 3
    Both of these interfaces are from ISO C, not POSIX. And there are profound functional differences when the files get very large. – zwol Jul 27 '10 at 23:12
  • Their difference is the way they can address the position: either by `long int` or by `fpos_t`. – math May 03 '16 at 08:49