Obsługa błędów w języku C zawsze była zadaniem programisty. W standardowej bibliotece nie ma wyjątków, błędy są zwracane przez kody zwrotu lub globalną zmienną errno (początek użycia — UNIX lat 70-tych, następnie POSIX i ANSI C). Takie mechanizmy są stosowane i dziś do zarządzania przepływem wykonania w sytuacjach awaryjnych.
Błędy podczas pracy ze standardowymi funkcjami (operacje na plikach, przydzielanie pamięci, funkcje łańcuchowe) mogą być niezauważalne bez odpowiedniej kontroli. Niewłaściwa obsługa — ignorowanie kodu zwrotu, niewłaściwa interpretacja errno, brak oczyszczania zasobów — prowadzi do błędnej pracy programu, awarii i podatności na ataki.
Prawidłowa obsługa błędów wymaga obowiązkowej analizy wartości zwracanych przez funkcje, użycia errno tylko bezpośrednio po awarii i informacyjnego wyświetlania błędów. Kody zwrotu są preferowane dla funkcji wewnętrznych — pozwalają na obsługę bez globalnych efektów ubocznych. errno jest częściej stosowane z wywołaniami systemowymi i funkcjami standardowej biblioteki. Po każdej potencjalnie niebezpiecznej operacji analizowany jest zwrot, a globalny stan (errno) nie powinien być nadpisywany przez pośrednie wywołania.
Przykład kodu:
#include <stdio.h> #include <errno.h> #include <string.h> FILE *open_file(const char *filename) { errno = 0; FILE *f = fopen(filename, "r"); if (!f) { fprintf(stderr, "Błąd: %s ", strerror(errno)); } return f; }
Kluczowe cechy:
Czy można używać errno dla funkcji użytkownika, jeśli chce się przekazywać błędy do góry?
Nie, errno jest przeznaczona tylko do standardowych wywołań bibliotecznych i systemowych. Jest globalna, może być nadpisana w dowolnym punkcie i nie nadaje się dla własnych funkcji.
Czy należy ustawiać errno przed każdym wywołaniem funkcji?
Nie, ale zaleca się resetowanie errno (na przykład do zera) przed wywołaniami, jeśli planowane jest analizowanie zmian. Nie każda funkcja zmienia errno przy sukcesie, tylko przy błędzie.
eerrno = 0; ... wywołanie niebezpiecznej funkcji ...
Czy można ufać errno po każdej funkcji?
Tylko dla tych funkcji, które zgodnie z normą wyraźnie ustawiają ją przy niepowodzeniu. Wiele funkcji standardowej biblioteki nie modyfikuje errno przy sukcesie. Dokumentacja to twój przyjaciel.
Otwieranie pliku bez sprawdzania wyniku, błędy nie są analizowane, program działa błędnie przy braku pliku:
Zalety:
Wady:
Po każdej krytycznej funkcji wynik jest sprawdzany, w przypadku błędu wyświetlana jest szczegółowa wiadomość z strerror(errno), wykonanie kończy się prawidłowo:
Zalety:
Wady: