| ← stdarg.h, limits.h, signal.h | C/C++ | knihovna string.h II → |
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, abychom 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>).
Knihovna <errno.h> definuje jedinou proměnnou, a to extern int errno;
Slůvka extern si zatím nevšímejte. Jenom
řeknu tolik, že se tak dá při vytváření knihovny nebo
předkompilované části programu pracovat s proměnnou, která ještě
nebyla nikde deklarována, takže fakticky v době překladu (knihovny,
části programu, ...) ještě nemusí existovat.
O vytváření a používání knihoven (ve Windows většinou mají
příponu .dll) jsme nemluvili a budu je probírat jen pod
operačním systémem Linux. Jde totiž o poměrně implementačně
závislou záležitost.
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á umí s touto proměnnou pracovat (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í kritické funkce. Protože další volaná funkce již může hodnotu errno přepsat.
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 v rámci definičního oboru funkce. |
|---|---|
| ERANGE | Označuje chybu v rámci oboru hodnot funkce. |
Podívejte se na příklad, ve kterém využijeme 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řeklad pomocí gcc, viz <math.h>.
1: /*------------------------------------------------*/ 2: /* errno1.c */ 4: #include <stdio.h> 5: #include <errno.h> 6: #include <math.h> 8: double logaritmus(double x) 9: { 10: double y; 11: y = log(x); 13: switch (errno) { 14: case EDOM: 15: printf("Doslo k chybe v ramci definicniho oboru funkce!\n"); 16: return 0; 17: case ERANGE: 18: printf("Doslo k chybe v ramci oboru hodnot funkce!\n"); 19: return 0; 20: case 0: 21: printf("Vse je v poradku. log(%f) = %f.\n", x, y); 22: return y; 23: default: 24: printf("Neocekavana chyba\n"); 25: return 0; 26: } 27: } 29: int main(void) 30: { 31: double x; 33: x = logaritmus(2.718281828); 34: x = logaritmus(-5); 35: x = logaritmus(9999999999); /* prilis velke cislo */ 36: x = logaritmus(0); 37: return 0; 38: } 40: /*------------------------------------------------*/
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!
Proměnná errno je typu int, takže může obsahovat celá čísla. To je sice také důležitá informace, ale nás spíše zajímá, co taková hodnota znamená. Už jme 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 k, 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) |
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 budeme 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í:
void perror(const char *s);
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ůžeme příklad errno1.c zjednodušit. Změníme v něm funkci logaritmus(), zbytek zůstane stejný.
1: /*------------------------------------------------*/ 2: /* errno2.c */ 4: #include <stdio.h> 5: #include <errno.h> 6: #include <math.h> 8: double logaritmus(double x) 9: { 10: double y; 11: y = log(x); 13: switch (errno) { 14: case 0: 15: perror(NULL); 16: printf("log(%f) = %f.\n", x, y); 17: return y; 18: default: 19: perror("Hlaseni"); 20: return 0; 21: } 22: } 24: int main(void) 25: { 26: double x; 28: x = logaritmus(2.718281828); 29: x = logaritmus(-5); 30: x = logaritmus(9999999999); /* prilis velke cislo */ 31: x = logaritmus(0); 32: return 0; 33: } 35: /*------------------------------------------------*/
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 návratové hodnoty funkcí. 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.
| ← stdarg.h, limits.h, signal.h | C/C++ | knihovna string.h II → |
