-2

When I use SEEK_END, I expect it to correspond to the position of the last character in the stream. But inside a printf it seems like it does not.

I have a file that contains 1010 characters. I open it with fopen, then I try to print the position of the last character of this file:

printf("Last position is: %d\n", SEEK_END);

The output is Last position is: 2 whereas I expect it to be Last position is: 1010. 2 does not correspond to the last line or last column, since I have 101 lines of 10 characters each. I don't know what it is.

Curiously, this code works well:

fseek(file, 0, SEEK_END);
printf("Last position is: %d\n", ftell(file));

The output is Last position is: 1010. But the problem here is that I am moving the virtual cursor in the file, which I do not want.

How can I print the value of SEEK_END without having to change the position of the virtual cursor, and more importantly, why do my printf outputs 2?

nounoursnoir
  • 671
  • 2
  • 10
  • 25

3 Answers3

5

You have a misunderstanding. SEEK_END is not a magical symbol that somehow stores the length of the file you're thinking of right now. It is a constant, used as a code to tell fseek() what reference point to use for the specified file offset.

If you want to determine the size of a file whose name you know, and you are on a POSIX system, then you can use fstat(). If all you have is a FILE *, then your best bet is probably to record the current position, seek to the end of the stream, determine the position, and then seek back to the starting point:

fpos_t current;
long end;

/* error checks omitted for brevity */
fgetpos(file, &current);
fseek(file, 0, SEEK_END);
end = ftell(file);
fsetpos(file, &current);

printf("Last position is: %ld\n", end);

Of course, all that depends on the stream being seekable. Not all of them are. If you have a non-seekable stream then very likely there is no meaningful sense of its last position to begin with.

There is also a potential issue with file offsets exceeding the size of a long. fgetpos() and fsetpos() can be expected not to be sensitive to that, but their accompanying fpos_t type may be an aggregate type (i.e. a struct), and thus not direct interrogable. You can work around that with lseek(), but that comes from POSIX, not standard C.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Ran the code above. Got this error: aggregate value used where an integer was expected. Got the answer from here [link](http://stackoverflow.com/questions/8621308/cast-fpos-t-to-int-or-char) – Nguai al May 05 '17 at 18:36
  • @Nguaial, yes, the first version of my code had that as a potential portability issue. It arises from the fact that `fpos_t` is not necessarily an arithmetic type. I have updated my code to avoid that issue, and added commentary about the related portability issues. – John Bollinger May 05 '17 at 18:58
3

SEEK_END is a parameter to fseek, it tells the fseek function how it should position in the file. You see 2 probably because in stdio.h it says #define SEEK_END 2 although the actual value is unspecified.

In order to get the offset you need to use ftell().

You can have a look at a specific implementation of fseek here.

Jens
  • 69,818
  • 15
  • 125
  • 179
AndersK
  • 35,813
  • 6
  • 60
  • 86
1

From here is possible to see that SEEK_END is an integer constant. It is not like a variable that holds the last position of your file. So, whenever you print SEEK_END value, it will be 2.

rgadelha
  • 11
  • 2