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.

Standardní chyby definované v <errno.h>
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>.

  1. /*------------------------------------------------*/
  2. /* c24/errno1.c                                   */
  3.  
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <math.h>
  7.  
  8. double logaritmus(double x)
  9. {
  10.     double y;
  11.     y = log(x);
  12.  
  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. }
  28.  
  29. int main(void)
  30. {
  31.     double x;
  32.  
  33.     x = logaritmus(2.718281828);
  34.     x = logaritmus(-5);
  35.     x = logaritmus(9999999999); /* prilis velke cislo */
  36.     x = logaritmus(0);
  37.     return 0;
  38. }
  39.  
  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!

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.

Standardní chyby definované v <errno.h>
EDOM Označuje chybu v rámci definičního oboru funkce.
ERANGE Označuje chybu v rámci oboru hodnot funkce.

Chyby definované v Linuxu
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ý.

  1. /*------------------------------------------------*/
  2. /* c24/errno2.c                                   */
  3.  
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <math.h>
  7.  
  8. double logaritmus(double x)
  9. {
  10.     double y;
  11.     y = log(x);
  12.  
  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. }
  23.  
  24. int main(void)
  25. {
  26.     double x;
  27.  
  28.     x = logaritmus(2.718281828);
  29.     x = logaritmus(-5);
  30.     x = logaritmus(9999999999); /* prilis velke cislo */
  31.     x = logaritmus(0);
  32.     return 0;
  33. }
  34.  
  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 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.

Komentář Hlášení chyby
Created: 29.8.2003
Last updated: 22.6.2014
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..