0

I need to figure out how does ftell() uses errno to distinguish between success and failure.

I know that the return value of ftell() would determine the success or failure, but it is possible to return the value of -1 (ftell() failure) even if on success, and the return is interpreted as a signed value.

So I check the return value of ftell() and if that is negative, I look at the errno, and if errno is non-zero, I determine the failure.

However, problem is that errno can be non-zero even from a previous error(doubtful about this). In this case how do I determine success or failure of ftell()?

anastaciu
  • 23,467
  • 7
  • 28
  • 53
Manan Shah
  • 35
  • 7
  • How the return of `ftell` can be negative if successful? File position can't be negative. – Eugene Sh. Apr 07 '21 at 20:21
  • Consider a 32-bit machine. There is a file of length 2^32-1. If you do a seek to the end of the file, then an ftell(), on success it returns 2^32-1, which **represented as a signed number** is -1. So ftell() succeeds but returns a value that, when signed, is interpreted as -1. – Manan Shah Apr 07 '21 at 20:23
  • 2
    In that case `ftell` will fail. It is limited by the [positive] range of `long`. See https://stackoverflow.com/questions/49121638/use-ftell-to-find-the-file-size , specifically the second bullet of the accepted answer. – Eugene Sh. Apr 07 '21 at 20:25

2 Answers2

2

As per Eugene Sh.'s arguments, it seems that it may be unneeded in this particular case, the return value of ftell should be enough.

Using errno, in general is done by setting its value to 0 before the function you expect to fail, and is documented as setting the value of errno.

Later you verify if its value was set, this value represents an implementation defined error code.

§7.21.9.4 - ftell()

Example:

#include <errno.h>
//...

FILE* f = fopen("fil.txt", "r"); // skipping error check

errno = 0;

long res = ftell(f)); // on failure ftell returns -1

if(errno > 0 && res == -1)
{
    // error occured
    perror("ftell"); // you can use perror to print error message related to the error code
}
anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • 1
    I am not sure the value of `errno` is guaranteed to remain zero in case of success, so checking it alone without the return value would not be right. In fact the answer to this question is talking about it: https://stackoverflow.com/questions/10211248/errno-value-is-not-updated – Eugene Sh. Apr 07 '21 at 20:40
  • @EugeneSh. I believe it will remain unchaged, maintaining its previous value, hence the need to reset it. – anastaciu Apr 07 '21 at 20:42
  • 1
    See the updated comment. You can't rely on `errno` alone to decide about the function success/failure. – Eugene Sh. Apr 07 '21 at 20:42
  • @EugeneSh., I see, I'm cheking it further. – anastaciu Apr 07 '21 at 20:44
  • 1
    Bottom line, the question is based on wrong assumption, this answer does not address it, and also providing a wrong solution. It should not be accepted. I suggest deletion. – Eugene Sh. Apr 07 '21 at 20:45
  • @EugeneSh., I don't understand your doubts, `errno` is set to 0 before `ftell` and `ftell` will only change errno in case of failure https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4 – anastaciu Apr 07 '21 at 20:50
  • 1
    No. The standard does not contain the important "only" word. – Eugene Sh. Apr 07 '21 at 20:50
  • @EugeneSh., Personally I think it may be a stretch to assume that a given function will be randomly changing the values of error flags for no reason, if that's the case, than `errno` is useless. – anastaciu Apr 07 '21 at 20:55
  • It is not useless, it is providing extra information if a failure is reported by the return value. Here is another link to convince you: https://man7.org/linux/man-pages/man3/errno.3.html : *The value in errno is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.* – Eugene Sh. Apr 07 '21 at 20:56
  • @EugeneSh., I saw that, I glazed over that part, I'm afraid, then the solution is to include the return value in the failure condition, is it not? – anastaciu Apr 07 '21 at 20:59
  • The point is that no solution is needed, because there is no problem. The usecase the OP is talking about is non-existent. `ftell` can't return negative value except on failure. – Eugene Sh. Apr 07 '21 at 21:00
  • I see you have added the check for return value (should be `long` btw). So now the usage is OK, it is just no check for `errno>0` is needed I think, it should set it on any failure. If you add the explanation about the OP's wrong assumption, this will be a valid answer – Eugene Sh. Apr 07 '21 at 21:08
  • @EugeneSh., well yes, but the OP was adamant in knowing how errno works and can be used, that's not so bad. If you believe I shoud delete the answer nonetheless, I'll do it, it's usage is indeed redundant in this case. – anastaciu Apr 07 '21 at 21:09
  • @EugeneSh. *a function that succeeds is allowed to change errno.* [Not if the function is documented to set `errno` on failure](https://port70.net/~nsz/c/c11/n1570.html#7.5p3): "The value of errno may be set to nonzero by a library function call whether or not there is an error, **provided the use of errno is not documented in the description of the function in this International Standard**." [`ftell()` is documented to set `errno` on failure](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4p3), and ***only*** on failure. So no, `ftell()` can not set `errno` to a non-zero value on success. – Andrew Henle Apr 07 '21 at 21:12
  • @AndrewHenle It is indeed documented, but it is not documented to *not* set `errno` on success. – Eugene Sh. Apr 07 '21 at 21:14
  • @EugeneSh. *ftell can't return negative value except on failure.* [***Yes it can***](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4p2): "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." – Andrew Henle Apr 07 '21 at 21:16
  • @AndrewHenle But can it return `-1` in this case, provided it is representnig failure? – Eugene Sh. Apr 07 '21 at 21:18
  • @EugeneSh. *but it is not documented to not set errno on success* I've [already quoted 7.5p3](https://port70.net/~nsz/c/c11/n1570.html#7.5p3). Functions are free to see `errno` on success ***only*** if they are ***not*** documented to set `errno` at all. [`ftell()`'s documentation](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4p3): "On failure, the ftell function returns -1L and stores an implementation-defined positive value in errno." `ftell()` is documented to set `errno` on failure, so per 7.5p3 it ***can not*** set `errno` on success. – Andrew Henle Apr 07 '21 at 21:20
  • Of course that doen't mean the Linux/glibc implementation behaves properly... – Andrew Henle Apr 07 '21 at 21:21
  • @AndrewHenle Sorry, I think you are affirming the consequent. The cited paragraph tells (let me rewrite it): *if the use of errno is not documented... then it can set `errno`*. This does not imply the converse: *If the use is documented ... then whatever*. It merely says that `errno` can be modified by any other function than the documented in the standard. – Eugene Sh. Apr 07 '21 at 21:25
  • In fact, it is rather "denying the antecedent", but whatever... – Eugene Sh. Apr 07 '21 at 21:38
0

So I check the return value of ftell() and if that is negative

This is the wrong test for text files as "For a text stream, its file position indicator contains unspecified information". On error, ftell() returns -1. With a text file, ftell() may return some other negative number, even on success.

long position = ftell(stream);
// if (position < 0) Error(); // Weak
if (position == -1) Error();  // Better test

The standard C library does not define that errno is set on an ftell() error. As OP's question is tagged linux, that OS offers various conditions for setting errno on an ftell() error. Then when errno is set by ftell(), -1 is returned.

ftell() ... shall return -1, and set errno to indicate the error.

// Remains a good test on *nix.
if (position == -1) Error();  // Better test

Yet OP has concern "it is possible to return the value of -1 (ftell() failure) even if on success,"

This is an extreme case where the file is exceptional long yet still legitimate. As the return value is long, the file length is expected to exceed 2G.

// *nix systems
errno = 0;
if (position == -1 && errno) {
  Error();  // Better *nix test
}

Many systems today that support such large files also employ a 64-bit long, negating the need for this && errno test (until files lengths exceed about 9,000,000,000,000,000,000 bytes - maybe 20 years).

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256