Leggere le pagine man e un po 'di codice non mi ha davvero aiutato a capire la differenza tra - o meglio, quando avrei dovuto usare - perror("...")
o fprintf(stderr, "...")
.
Leggere le pagine man e un po 'di codice non mi ha davvero aiutato a capire la differenza tra - o meglio, quando avrei dovuto usare - perror("...")
o fprintf(stderr, "...")
.
Risposte:
La chiamata perror
ti darà il valore interpretato di errno
, che è un valore di errore locale del thread scritto dalle chiamate di sistema POSIX (cioè, ogni thread ha il proprio valore per errno
). Ad esempio, se hai effettuato una chiamata a open()
e si è verificato un errore (ovvero è stato restituito -1
), puoi chiamare perror
subito dopo per vedere qual è stato l'errore effettivo. Tieni presente che se nel frattempo chiami altre chiamate di sistema, il valore in errno
verrà sovrascritto e la chiamata perror
non sarà di alcuna utilità per diagnosticare il problema se un errore è stato generato da una precedente chiamata di sistema.
fprintf(stderr, ...)
d'altra parte può essere utilizzato per stampare i propri messaggi di errore personalizzati. Stampando su stderr
, si evita che l'output di segnalazione degli errori venga mischiato con l'output "normale" che dovrebbe avere stdout
.
Tieni presente che fprintf(stderr, "%s\n", strerror(errno))
è simile a perror(NULL)
poiché una chiamata a strerror(errno)
genererà il valore di stringa stampato per errno
e puoi quindi combinarlo con qualsiasi altro messaggio di errore personalizzato tramite fprintf
.
strerror
non è necessario essere thread-safe. È stupido, ma questo è lo standard. strerror_l
può essere utilizzato invece come sostituto immediato sui sistemi POSIX 2008. strerror_r
è disponibile anche su sistemi meno recenti, ma presenta problemi davvero fastidiosi con alcuni sistemi che ne hanno versioni non conformi.
perror
aggiunge '\n'
alla fine quindi il formato sarebbe "%s\n"
, no?
strerror_s
realtà non è poi così male come interfaccia.
_s
spazzatura nello standard era fondamentalmente un gioco di MS ("Se adotti le nostre interfacce, prenderemo in considerazione l'idea di far sì che i nostri prodotti supportino il tuo standard") e ovviamente ora non stanno seguendo. In realtà sono d'accordo che questa interfaccia non è male in sé. Ciò che è negativo è la propaganda (sotto forma di avvertimenti del compilatore) secondo cui la maggior parte della libreria standard è "non sicura" e che l'intera famiglia di _s
funzioni dovrebbe essere utilizzata al posto di quelle standard.
Fanno cose piuttosto diverse.
Si utilizza perror()
per stampare un messaggio a stderr
cui corrisponde errno
. Utilizzi fprintf()
per stampare qualsiasi cosa su stderr
o qualsiasi altro flusso. perror()
è una funzione di stampa molto specializzata:
perror(str);
è equivalente a
if (str)
fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
fprintf(stderr, "%s\n", strerror(errno));
perror(const char *s)
: stampa la stringa che gli dai seguita da una stringa che descrive il valore corrente di errno
.
stderr
: è un flusso di output utilizzato per reindirizzare i propri messaggi di errore (predefinito al terminale).
Pertinente:
char *strerror(int errnum)
: dagli un numero di errore e restituirà la stringa di errore associata.
perror () scrive sempre su stderr; strerr (), usato insieme a fprintf (), può scrivere su qualsiasi output, incluso stderr ma non esclusivamente.
fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")
Inoltre, perror impone la propria formattazione del testo "testo: descrizione errore"
La funzione Perror impiega più tempo per eseguire la chiamata va dallo spazio utente allo spazio kernel dove fprintf chiama goest da api a kernal
If you use a function that effects errno then it makes sense to use perror
Se usi una funzione che non ha effetto su errno e restituisce semplicemente un codice di errore dovresti usare fprintf (stderr, fmt, ...). Ad esempio, strtol restituirà LONG_MAX o LONG_MIN se una stringa è fuori intervallo e imposta errno su ERANGE. Quindi se strtol fallisce a causa di fuori intervallo, userei perror.