what is difference between fgetpos/fsetpos and ftell/fseek
Asked Answered
O

4

48

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()?

Obduce answered 27/7, 2010 at 22:49 Comment(1)
See #12119632 It's answer is way better than the accepted answer here.Enliven
O
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.

Obduce answered 27/7, 2010 at 22:52 Comment(3)
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.Enliven
@Enliven Yes indeed, this answer is wrong. As far as I understand my answer below is the only correct one.Goiter
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).Ghee
G
31

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.

Goiter answered 10/1, 2014 at 11:3 Comment(6)
Not actually exact answer for the question, but very good as tip! Thanks!Caldron
@Caldron 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).Enliven
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 possiblGhee
I cannot open the link :/ Any copy of the reasoning?Ten
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.Earpiercing
Actually the answer by @Obduce given 4 years before yours is correct (if not, would you please give the exact place where it's wrong). -1 for unreasonable invalidating other answers.Victualer
O
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.

Obduce answered 27/7, 2010 at 22:52 Comment(3)
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.Enliven
@Enliven Yes indeed, this answer is wrong. As far as I understand my answer below is the only correct one.Goiter
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).Ghee
S
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.

Silly answered 13/6, 2014 at 3:6 Comment(0)
K
-4

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

Kisangani answered 27/7, 2010 at 22:52 Comment(2)
Both of these interfaces are from ISO C, not POSIX. And there are profound functional differences when the files get very large.Dobby
Their difference is the way they can address the position: either by long int or by fpos_t.Ghee

© 2022 - 2024 — McMap. All rights reserved.