groff
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [groff] [off-topic] Reliable use of errno


From: Ralph Corderoy
Subject: Re: [groff] [off-topic] Reliable use of errno
Date: Sun, 19 Aug 2018 14:49:48 +0100

Hi Carsten,

> Many system calls (e.g. close(2),
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html)
> return 0 on success and -1 on error and set errno.

Well done for referring to POSIX.  Your Unix system might make their man
pages available alongside its own, e.g. I've close(3p) here as well as
close(2).

> My understanding is that errno is only reliably set when the system
> call returns -1, not for < -1 nor for > 0

In close(3p)'s case, it's documented as only returning 0 or -1 so those
others can't occur, and there's no reason to think errno would be set if
they did.

> so I do only check the error condition with "if (close(fd) == -1)"
> ignoring all other values.

I do.  It makes the intent more clear and means the human reader doesn't
have to wonder what other values the author might have expected.  Not so
relevant with close(2), but in general.

The Unix Programmer's Manual, 5th Ed., documents close(Ⅱ):

    DIAGNOSTICS
        The error bit (c-bit) is set for an unknown file descriptor.
        From C a -1 indicates an error, 0 indicates success.

So the carry bit was set, and the C wrapper to the system call in libc.a
translated that to -1 as CPU flags weren't available in C.  PDP/11's
`bec' and `bes', `branch if error clear/set', were synonyms for `bcc'
and `bcs'.

Historically, I suspect the `< 0' style was due to habit in only
checking the carry bit in assembler, or directing the C compiler to a
more efficient check than testing against -1.  Testing against -1 means
a -1 must be obtained.  With x86_64 today, gcc still takes a byte more
for the equivalence test on x86_64.

    $ cat neg.c
    int neg(int i, int r, int s)
    {
        if (i < 0)
            return r;
        return s;
    }

    int neg1(int i, int r, int s)
    {
        if (i == -1)
            return r;
        return s;
    }
    $ 
    $ gcc -O3 -c neg.c
    $ objdump -d neg.o | sed '1,/Disass/d'

    0000000000000000 <neg>:
       0:  89 d0                 mov    %edx,%eax   ; return = s
       2:  85 ff                 test   %edi,%edi   ; flags = i & i
       4:  0f 48 c6              cmovs  %esi,%eax   ; if flags.sign: return = r
       7:  c3                    retq
       8:  0f 1f 84 00 00 00 00  nopl   0x0(%rax,%rax,1)
       f:  00 

    0000000000000010 <neg1>:
      10:  89 d0                 mov    %edx,%eax          ; return = s
      12:  83 ff ff              cmp    $0xffffffff,%edi   ; flags = i - -1
      15:  0f 44 c6              cmove  %esi,%eax          ; if flags.zero: 
return = r
      18:  c3                    retq   
    $ 

(I'm surprised gcc and others haven't added a pragma so a function can
declare [-1, INT_MAX] is returned so they can optimise a `== -1' test.)

> So when can I rely on errno to be set, for -1, for "< 0" or for "!=
> 0"?

When close() returns -1, as documented.  Also, errno should only be read
when a function's return value has indicated it is valid, says POSIX's
errno(3p).

> In case of library functions (e.g. fclose(3),
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html)
> we have a similar situation with the return values 0 and EOF.
>
> I did test for errors with "if (fclose(fh) == EOF)", others are
> testing for "!= 0". When can I rely here for errno to be set, only in
> case of EOF or als for "!= 0"?

Only in the case of EOF.  But POSIX is also stating only 0 or EOF may be
returned, so `!= 0', or just `if (fclose(fp))', must be EOF.

In summary, code to the documented interface.

-- 
Cheers, Ralph.
https://plus.google.com/+RalphCorderoy



reply via email to

[Prev in Thread] Current Thread [Next in Thread]