La libreria C non imposta errno
su 0 per ragioni storiche 1 . POSIX non rivendica più che le sue librerie non modificheranno il valore in caso di successo e la nuova pagina man di Linux per errno.h
riflette questo:
The <errno.h>
header file defines the integer variable errno
, which is set by system calls and some library functions in the event of an error to indicate what went wrong. Its value 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
.
La Razionale ANSI C afferma che il comitato si sentiva era più pratico adottare e standardizzare la pratica esistente dell'uso di errno
.
The error reporting machinery centered about the setting of errno
is generally regarded with tolerance at best. It requires a ''pathological coupling'' between library functions and makes use of a static writable memory cell, which interferes with the construction of shareable libraries. Nevertheless, the Committee preferred to standardize this existing, however deficient, machinery rather than invent something more ambitious.
C'è quasi sempre un modo per controllare l'errore al di fuori di controllare se è stato impostato errno
. Controllare se errno
è stato impostato non è sempre affidabile, poiché alcune chiamate richiedono di chiamare un'API separata per ottenere il motivo dell'errore. Ad esempio, ferror()
viene utilizzato per verificare la presenza di un errore se ottieni un risultato breve da fread()
o fwrite()
.
È interessante notare che il tuo esempio di utilizzo di strtod()
è uno dei casi in cui l'impostazione errno
su 0 prima che la chiamata sia richiesta per rilevare correttamente se si è verificato un errore. Tutte le funzioni strto*()
stringa su numero hanno questo requisito, poiché viene restituito un valore di ritorno valido anche a fronte di un errore.
errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
/*...parse error */
} else if (errno == ERANGE) {
if (x == 0) {
/*...underflow */
} else if (x == HUGE_VAL) {
/*...positive overflow */
} else if (x == -HUGE_VAL) {
/*...negative overflow */
} else {
/*...unknown range error? */
}
}
Il codice sopra riportato si basa sul comportamento di strtod()
come documentato su Linux . Lo standard C stabilisce che l'underflow non può restituire un valore maggiore del più piccolo% positivo% co_de e se double
è impostato su errno
è l'implementazione definita 2 .
In realtà esiste un ampio articolo di consulenza sulla cert che raccomanda sempre impostando ERANGE
su 0 prima di una chiamata alla libreria e verificandone il valore dopo la chiamata, si è verificato un errore . Questo perché alcune chiamate di libreria imposteranno errno
anche se la chiamata stessa ha avuto successo 3 .
The value of errno
is 0 at program startup, but it is never set to 0 by any library function. 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 the C Standard. It is meaningful for a program to inspect the contents of errno
only after an error has been reported. More precisely, errno
is meaningful only after a library function that sets errno
on error has returned an error code.
1. In precedenza ho affermato che era per evitare di mascherare un errore da una chiamata precedente. Non riesco a trovare alcuna prova a sostegno di questa affermazione. Ho anche avuto un esempio falso errno
.
2. Grazie a @chux per averlo indicato. Il riferimento è C.11 §7.22.1.3 ¶10.
3. Indicato da @KeithThompson in un commento.