La libreria C non è impostata errno
su 0 per motivi storici 1 . POSIX non afferma più che le sue librerie non modificheranno il valore in caso di successo e la nuova pagina man di Linuxerrno.h
riflette questo:
Il <errno.h>
file di intestazione definisce la variabile intera errno
, che viene impostata dalle chiamate di sistema e da alcune funzioni della libreria in caso di errore per indicare cosa è andato storto. Il suo valore è significativo solo quando il valore restituito della chiamata indicava un errore (ovvero, -1
dalla maggior parte delle chiamate di sistema -1
o NULL
dalla maggior parte delle funzioni di libreria); una funzione che riesce è permesso di cambiare errno
.
L' ANSI C Rationale afferma che il comitato ha ritenuto più pratico adottare e standardizzare la pratica esistente dell'uso errno
.
Il meccanismo di segnalazione degli errori incentrato sull'impostazione di errno
è generalmente considerato con tolleranza nella migliore delle ipotesi. Richiede un `` accoppiamento patologico '' tra le funzioni della libreria e si avvale di una cella di memoria scrivibile statica, che interferisce con la costruzione di librerie condivisibili. Tuttavia, il Comitato ha preferito standardizzare questa macchina esistente, per quanto carente, piuttosto che inventare qualcosa di più ambizioso.
Esiste quasi sempre un modo per verificare la presenza di errori al di fuori del controllo se errno
impostato. Controllare se errno
impostato non è sempre affidabile, poiché alcune chiamate richiedono la chiamata di un'API separata per ottenere il motivo dell'errore. Ad esempio, ferror()
viene utilizzato per verificare la presenza di un errore se si ottiene un risultato breve da fread()
o fwrite()
.
È interessante notare che il tuo esempio di utilizzo strtod()
è uno dei casi in cui errno
è necessario impostare 0 prima della chiamata per rilevare correttamente se si è verificato un errore. Tutte le strto*()
funzioni da stringa a numero hanno questo requisito, perché 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 solo che il flusso insufficiente non può restituire un valore maggiore del positivo più piccolo double
e se errno
è impostata o meno l' ERANGE
implementazione è definita 2 .
Esiste in realtà un approfondito avviso di avviso che consiglia di impostare sempre errno
su 0 prima di una chiamata in biblioteca e di controllarne il valore dopo che la chiamata indica che si è verificato un errore . Questo perché alcune chiamate in libreria verranno impostate errno
anche se la chiamata stessa ha avuto esito positivo 3 .
Il valore di errno
è 0 all'avvio del programma, ma non è mai impostato su 0 da nessuna funzione di libreria. Il valore di errno
può essere impostato su un valore diverso da zero da una chiamata della funzione di libreria in presenza o meno di un errore, purché l'uso di errno
non sia documentato nella descrizione della funzione nella norma C. È significativo che un programma controlli i contenuti errno
solo dopo che è stato segnalato un errore. Più precisamente, ha errno
senso solo dopo che una funzione di libreria impostata errno
su errore ha restituito un codice di errore.
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 printf()
esempio falso .
2. Grazie a @chux per averlo segnalato. Il riferimento è C.11 §7.22.1.3 ¶10.
3. Segnalato da @KeithThompson in un commento.
errno
, puoi sempre impostarlo su zero te stesso.