Knihovna errno.h
Mnoho funkcí může z nějakého důvodu selhat. Například funkce která má otevřít soubor může selhat, protože soubor neexistuje, nebo k němu program nemá přístupová práva. Nebo funkce, která má spočítat logaritmus čísla, dostane jako argument zápornou hodnotu, nebo nulu. K tomu, abyste mohli zjistit, zda a k jaké došlo chybě, slouží knihovna <errno.h>. (Nepleťte si, prosím, knihovnu <errno.h> a knihovnou <erorr.h>).
Proměnná errno
Knihovna <errno.h> definuje jedinou proměnnou, a to
extern int errno;
.
Extern
Jak víte, program může využívat ke svému běhu různé knihovny.
Například /lib/i386-linux-gnu/libc.so.6
.
Taková knihovna může obsahovat nejenom funkce, ale i proměnné.
Jak taky víte, funkce z knihoven musíte před použitím ve zdrojovém
kódu alespoň deklarovat (než je definujete nebo připojíte knihovnu,
kam byli překompilovány). Proměnné, které máte, nebo budete mít,
v nějaké knihovně (nebo budou definované v nějakém jiném zdrojovém
souboru), deklarujete pomocí klíčového slova extern
.
(Globální) proměnné extern
mohou být deklarovány mnohokrát.
Musí být definovány právě jednou. (Překladač se může mnohokrát dozvědět,
že bude existovat nějaká globální proměnná daného jména a typu, ale jen
jednou si pro ni alokuje místo v paměti.)
Použití errno
Pokud začleníte do svého programu hlavičkový soubor <errno.h>,
můžete proměnnou errno
využívat k odhalování
chyb. Při startu programu je proměnná errno
nastavena na nulu (tr. bezchybný stav).
Když proběhne nějaká funkce, která je naprogramovná tak,
aby s touto proměnnou pracovala (může to být i vámi vytvořená funkce),
nastaví proměnnou na nějakou hodnotu.
Například 0, když se nic špatného nestalo. Z toho vyplývá,
že když chcete odhalit chybu v nějaké funkci, musíte proměnnou
errno
testovat ihned po skončení funkce.
Protože další volaná funkce může hodnotu errno
přepsat.
Ne všechny funkce nastaví při úspěchu errno
na nulu.
Proto musíte před zavoláním funkce errno
nastavit na 0 „ručně“
(Podívejte se třeba na příklad v manuálové stránce funkce strtol()
.)
Použití errno
se hodí především tam,
kde funkce nemůže oznámit chybu svou návratovou hodnotou.
Proměnná errno
tedy obsahuje nějaké
číslo určující chybu. Aby byla práce s touto proměnnou
přehlednější, byli definovány dvě standardní makra,
která reprezentují možné chyby.
EDOM | Označuje chybu argumentu, který je mimo platný rozsah. |
---|---|
ERANGE | Výsledek funkce je příliš velký. |
Kromě těchto dvou existuje ještě veeelká řada dalších, definovaných normou POSIX (tedy existující na unixech, ale nejspíš ne ve Windows).
Podívejte se na příklad, ve kterém se využije proměnné
errno
k odhalení a určení chyby ve funkci
log z knihovny <math.h>.
Nezapomeňte při překladu v Linuxu, že je
třeba použít přepínače -lm při překladu pomocí gcc
,
viz <math.h>.
- /*------------------------------------------------*/
- /* c24/errno1.c */
- #include <stdio.h>
- #include <errno.h>
- #include <math.h>
- {
- double y;
- case EDOM:
- case ERANGE:
- return y;
- }
- }
- {
- double x;
- x = logaritmus(2.718281828);
- x = logaritmus(-5);
- x = logaritmus(9999999999); /* prilis velke cislo */
- x = logaritmus(0);
- }
- /*------------------------------------------------*/
Výstup z programu:
Vse je v poradku. log(2.718282) = 1.000000. Doslo k chybe v ramci definicniho oboru funkce! Doslo k chybe v ramci definicniho oboru funkce! Doslo k chybe v ramci oboru hodnot funkce!
Co může obsahovat errno
Proměnná errno
je typu int, takže může
obsahovat celá čísla.
To je sice také důležitá informace, ale zajímavější je, co taková
hodnota znamená. Už jste se setkali se dvěma hodnotami –
EDOM a ERANGE. Různé hlavičkové
soubory si definují další možné chybové hodnoty. Jaké chyby v té či
oné funkci můžou nastat a co znamenají se dočtete v manuálu ke
konkrétní funkci. Jediné, na co se můžete spolehnout je, že nula
značí bezchybný stav. Tedy skoro. Některé funkce totiž s proměnnou
errno
nepracují, takže její hodnotu nezmění ani při chybě.
V následující tabulce vám ukážu některé makra převzatá z
linuxového manuálu k souboru <errno.h>. Mnohé z těchto maker
jsou přístupné jen a jen pod unixovými operačními systémy (pozn.:
Linux vychází z Unixu). Přesněji řečeno v systémech podporujících
nejen standard ANSI C, ale i POSIX.1. Význam některých z těchto
maker vám může ujít, neboť jsou využívány funkcemi, které ještě
neznáte (například pro práci se soubory). Znovu vás proto odkazuji
na manuály k funkcím, kde se vždy dočtete, jaké
chybové hlášení ta či ona funkce může do proměnné
errno
zapisuje (pokud vůbec nějaké). Berte následující tabulku pouze
jako ilustrativní záležitost.
EDOM | Označuje chybu v rámci definičního oboru funkce. |
---|---|
ERANGE | Označuje chybu v rámci oboru hodnot funkce. |
E2BIG | Příliš mnoho argumentů |
---|---|
EACCES | Přístup odmítnut |
EBADF | Špatný deskriptor souboru |
ECANCELED | Operace přerušena |
ECHILD | Žádný podproces |
EEXIST | Soubor existuje |
EFAULT | Špatná adresa (do paměti) |
EFBIG | Soubor je příliš veliký |
EINVAL | Chybný argument |
EIO | Chyba vstupu/výstupu |
EISDIR | Je to adresář |
EMFILE | Příliš mnoho otevřených souborů |
ENAMETOOLONG | Příliš dlouhé jméno souboru |
ENOENT | Soubor nebo adresář nebyl nalezen |
ENFILE | Příliš mnoho otevřených souborů v systému |
ENODEV | Zařízení nebylo nalezeno |
ENOEXEC | Chyba formátu spustitelného souboru |
ENOMEM | Nedostatek místa (v paměti) |
ENOSPC | Nedostatek místa na zařízení (třeba na disku) |
ENOTDIR | Není adresářem |
ENOTEMPTY | Adresář není prázdný |
EPERM | Operace není přístupná |
EROFS | Systém je jen pro čtení (neumožňuje zápis) |
Chybové hlášení pomocí perror()
Všechna chybová hlášení jsou uložena v proměnné
const char *sys_errlist[];
.
Počet chybových hlášení (tedy počet řetězců, na které ukazuje
pole sys_errlist
) je uložen v proměnné
typu int, sys_nerr
. Poslední chybové hlášení je
tedy v sys_errlist[sys_nerr-1];
Proměnné sys_errlist
i
sys_nerr
jsou definovány v knihovně <stdio.h>.
Funkce perror()
je deklarována
v knihovně <stdio.h> (tu budu
probírat podrobně později)
a slouží k vypsání chybového hlášení na základě obsahu proměnné
errno. Deklarace funkce perror()
je následující:
Funkce perror()
pošle nejdříve řetězec s,
za něj přidá dvojtečku a poté chybové hlášení do standardního chybového
proudu stderr
(to je nejčastěji na obrazovku). Pokud má
s hodnotu NULL, pak vypíše jen chybové
hlášení. V případě, že k žádné chybě nedošlo (errno == 0) se vypíše něco jako
„Úspěch“ (Success).
Jak budou hlášení vypadat závisí mimo jiné třeba na nastavení národního prostředí pomocí knihovny <local.h>. Tomu se budu věnovat až v části věnované programování v Linuxu.
Díky funkci perror()
můžete příklad
errno1.c zjednodušit.
Změním v něm funkci logaritmus()
,
zbytek zůstane stejný.
- /*------------------------------------------------*/
- /* c24/errno2.c */
- #include <stdio.h>
- #include <errno.h>
- #include <math.h>
- {
- double y;
- return y;
- }
- }
- {
- double x;
- x = logaritmus(2.718281828);
- x = logaritmus(-5);
- x = logaritmus(9999999999); /* prilis velke cislo */
- x = logaritmus(0);
- }
- /*------------------------------------------------*/
Možný výstup z programu:
Success log(2.718282) = 1.000000. Hlaseni: Numerical argument out of domain Hlaseni: Illegal seek Hlaseni: Numerical result out of range
Žádný program by si neměl dovolit ignorovat kontrolu chyb. K chybám dochází častěji, než si můžete myslet. Mezi běžné chyby patří například nedostatek místa na disku, odmítnuté internetové spojení, nedostatečná přístupová práva atp. Se všemi problémy by se vaše programy měli umět co nejlépe vyrovnat. Alespoň nějaké chybové hlášení by měli zobrazit. Ne že je necháte v tichosti zhebnout.