Kiedy należy używać perror („…”) i fprintf (stderr, „…”)?

105

Czytanie stron podręcznika man i części kodu tak naprawdę nie pomogło mi w zrozumieniu różnicy między - lub lepiej, kiedy powinienem używać - perror("...")lub fprintf(stderr, "...").

freeboy1015
źródło

Odpowiedzi:

113

Wywołanie perrorda ci zinterpretowaną wartość errno, która jest wartością błędu lokalnego dla wątku zapisywaną przez wywołania systemowe POSIX (tj. Każdy wątek ma swoją własną wartość dla errno). Na przykład, jeśli wykonałeś wywołanie open()i wystąpił błąd (tj. Zwrócił -1), możesz następnie zadzwonić perrornatychmiast po tym, aby zobaczyć, jaki był rzeczywisty błąd. Należy pamiętać, że jeśli w międzyczasie wywołasz inne wywołania systemowe, wartość w errnozostanie nadpisana, a wywołanie perrornie będzie przydatne w diagnozowaniu problemu, jeśli błąd został wygenerowany przez wcześniejsze wywołanie systemowe .

fprintf(stderr, ...)z drugiej strony może służyć do drukowania własnych niestandardowych komunikatów o błędach. Drukując do stderr, unikniesz pomieszania wyników raportowania błędów z "normalnymi" wynikami, które powinny się pojawić stdout.

Należy pamiętać, że fprintf(stderr, "%s\n", strerror(errno))jest to podobne do, perror(NULL)ponieważ wywołanie funkcji strerror(errno)wygeneruje wydrukowaną wartość ciągu dla errno, którą można następnie połączyć z dowolnym innym niestandardowym komunikatem o błędzie za pośrednictwem fprintf.

Jason
źródło
3
och, rozumiem. Funkcja perror działa różnie w zależności od wartości errno. If you use a function that effects errno then it makes sense to use perrorJeśli używasz funkcji, która nie wywołuje efektu errno i po prostu zwraca kod błędu, powinieneś użyć fprintf (stderr, fmt, ...). Na przykład strtol zwróci LONG_MAX lub LONG_MIN, jeśli łańcuch jest poza zakresem i ustawi errno na ERANGE. Więc jeśli strtol zawiedzie z powodu braku zasięgu, użyłbym perror.
freeboy1015
6
Jeden szczegół strerrornie jest wymagany, aby był bezpieczny dla wątków. To głupie, ale to standard. strerror_lmoże być używany jako zamiennik typu drop-in w systemach POSIX 2008. strerror_rjest również dostępny na starszych systemach, ale ma naprawdę nieprzyjemne problemy z niektórymi systemami z niezgodnymi wersjami.
R .. GitHub STOP POMAGANIE LODOM
też jako czubek, myślę, że perrordodaje '\n'na końcu więc format byłby "%s\n", nie?
Jens Gustedt
1
@R .., ha, już to zrobiłem i o ile wiem, nic mi nie płacą. A ponieważ wydaje się, że MS całkowicie odcina wsparcie dla C, na końcu będę jedyny :) strerror_snie jest tak zły jako interfejs.
Jens Gustedt
2
Cięcie wsparcia całkowicie? Wygląda na to, że znowu oszukali komitet. Wprowadzenie ich _sśmieci do standardu było w zasadzie grą MS („Jeśli zaadoptujesz nasze interfejsy, rozważymy, czy nasze produkty będą obsługiwać Twój standard”) i oczywiście teraz nie nadążają. Właściwie zgadzam się, że ten jeden interfejs sam w sobie nie jest zły. Zła to propaganda (w postaci ostrzeżeń kompilatora), że większość biblioteki standardowej jest „niebezpieczna” i że _szamiast standardowych należy używać całej rodziny funkcji.
R .. GitHub STOP HELPING ICE
40

Robią raczej różne rzeczy.

Używasz perror()do drukowania wiadomości, stderrktóra odpowiada errno. Używasz fprintf()do drukowania czegokolwiek do stderrlub dowolnego innego strumienia. perror()to bardzo wyspecjalizowana funkcja drukowania:

perror(str);

jest równa

if (str)
    fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
    fprintf(stderr, "%s\n", strerror(errno));
freeboy1015
źródło
12

perror(const char *s): wypisuje podany ciąg, po którym następuje ciąg opisujący bieżącą wartość errno.

stderr: jest to strumień wyjściowy używany do przesyłania własnych komunikatów o błędach (domyślnie do terminala).

Istotnych:

char *strerror(int errnum): nadaj mu numer błędu, a zwróci powiązany ciąg błędu.

Adib Saad
źródło
2

perror () zawsze zapisuje na stderr; strerr (), używana razem z fprintf (), może zapisywać na dowolnym wyjściu - w tym stderr, ale nie wyłącznie.

fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")

Ponadto perror narzuca swój własny tekst, tworząc tekst „tekst: opis błędu”

Sebastien
źródło
-2

Funkcja Perror zajmuje więcej czasu, aby wykonać wywołanie przechodzi z przestrzeni użytkownika do przestrzeni jądra, podczas gdy wywołania fprintf przechodzą do api do kernal

vivek singh
źródło