7. Paměť programu, standardní knihovny C. Rekurze

Jan Faigl 2025/09/19 19:45

Jan Faigl 2023/11/16 15:32 / Aktualizace: Doplnění volání fill_numbers() a print() v save_struct.c.

Jan Faigl 2023/11/19 20:00 Umístění errno.h

Chybové kódy standardní knihovny C jsou definovány v souboru errno.h, umístění souboru s definicí chyb je však na různých systémch různé. V unixovových systém se jedná zpravidla o /usr/include/errno.h případně /usr/include/sys/errno.h, popis jednotlivých konstant a hodnot lze také najít např. v man errno. V distribucích Linuxu je situace trošku složitější, neboť umístění záleží na konkrétní distribuci, např. lP5oGIqdWEU

  • /usr/include/asm/errno.h
  • /usr/include/asm-generic/errno-base.h
  • /usr/include/asm-generic/errno.h
  • /usr/lib/bcc/include/linux/errno.h
  • /usr/include/sys/errno.h
  • /usr/include/asm-i386/errno.h

Konkrétní soubor můžeme najít například příkazem

grep -R 17 /usr/include/**/errno*.h
/usr/include/asm-generic/errno-base.h:#define	EEXIST		17	/* File exists */
/usr/include/asm-generic/errno.h:#define	EUCLEAN		117	/* Structure needs cleaning *

jehož výstup nám napoví, že na tomto konkrétním Linuxu jsou rozděleny chybové kódy do souborů errno-base.h (obsahující základní kódy) a errno.h obsahující rozšířené kódy, tj. kódy s vyšší hodnotou.

Dále je většinou v Linuxu standardní knihovna libc realizována jako GNU libc (glibc ), což přináší některé zajímavé funkce , které na druhou stranu nejsou dostupné na jiných OS, nelinuxového typu, např. OS X.

Q: Je nějaké omezení na hloubku rekurzivního volání?

Ano, při volání funkce se minimálně ukládá na zásobník adresa odkud funkci voláme, aby mohlo dojít k návratu z volání funkce. Dále se při každém volání mohou vytvářet na zásobníku lokální proměnné. Tedy omezení je dáno velikostí zásobníku. Omezení si můžeme vyzkoušet následujícím programem.

#include <stdio.h>
 
void printValue(int v);
 
int main(void)
{
   printValue(1);
}
 
void printValue(int v)
{
   printf("value: %i\n", v);
   printValue(v + 1);
}

a spuštěním s omezenou velikostí zásobníku

ulimit -s 1000; ./a.out | tail -n 3
value: 31730
value: 31731
Segmentation fault

a s větší velikostí.

ulimit -s 10000; ./a.out
value: 319816
value: 319817
Segmentation fault

V obou případech končí volání chybou. Ve druhém případě došlo k hlubšímu zanoření. Zotavení z chybějícího místa na zásobníku je velmi náročné, narozdíl od dynamické alokace. Výchozí hodnota zásobníku je nastavana na relativně dostačující velikost pro běžné programy. Nicméně v případě rekurzivního řešení je dobré pamatovat, že místo na zásobníku není neomezené. Proto je vždy vhodné rozumět úloze a konkrétním (typickým) vstupům a prostředí. Například na základě velikosti vstupu můžeme odhadnout, potřebnou velikost zásobníku a případně uživatele informovat. Asi nejhorší případ je, když program padá a netušíme proč tomu tak je.

courses/b0b36prp/lectures/lec07.txt · Last modified: 2025/09/19 19:46 by faiglj