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, "...")
.
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, "...")
.
Odpowiedzi:
Wywołanie perror
da 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ć perror
natychmiast 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 errno
zostanie nadpisana, a wywołanie perror
nie 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
.
strerror
nie jest wymagany, aby był bezpieczny dla wątków. To głupie, ale to standard. strerror_l
może być używany jako zamiennik typu drop-in w systemach POSIX 2008. strerror_r
jest również dostępny na starszych systemach, ale ma naprawdę nieprzyjemne problemy z niektórymi systemami z niezgodnymi wersjami.
perror
dodaje '\n'
na końcu więc format byłby "%s\n"
, nie?
strerror_s
nie jest tak zły jako interfejs.
_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 _s
zamiast standardowych należy używać całej rodziny funkcji.
Robią raczej różne rzeczy.
Używasz perror()
do drukowania wiadomości, stderr
która odpowiada errno
. Używasz fprintf()
do drukowania czegokolwiek do stderr
lub 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));
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.
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”
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
If you use a function that effects errno then it makes sense to use perror
Jeś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.