Jak na pro­jek­ty v ja­zy­ce C

© Damig, 2004 – 2016
Koncept

Ladění a testování programů
Instrumentace programů

Instrumentace programů je principiálně nejjednodušší technika ladění, kterou každý začátečník použije asi nejdříve (ale velmi, dokonce VELMI často ji používají i zkušení programátoři). Spočívá v doplnění zdrojového kódu programu o kontrolní výpisy. Existují programy, které umí speciálně formátované kontrolní výpisy zpracovávat a zobrazit je ve formě grafu časové souslednosti nebo z nich vytáhnout různé zajímavé statistické údaje. Ty se pak dají použít nejenom pro ladění, ale i pro profilování programů.

int x = 10, y = 5;
printf("x = %d, y = %d\n", x, y); // kontrolní výpis
x = y++ - (x + 3);
printf("x = %d, y = %d\n", x, y); // kontrolní výpis
...
Instrumentace, neboli kontrolní výpisy obsahu proměnných na standardní nebo chybový výstup programu, případně do logovacího souboru.

Princip je jednoduchý, ale překvapivě účinný. Pro ladění programů tímto způsobem není potřeba žádný debugger ani jiný dodatečný software. Na druhou stranu ovšem mohou existovat programy, které jsou schopny instrumentace vyhodnocovat a prezentovat získané údaje názorněji. Další výhodou kontrolních tisků je možnost analyzovat dlouhý běh programu nebo složité chování, jako například běh paralelního programu. V těchto případech je použití konvenčního debuggeru dost problematické.

Pokud si pro ladící výpisy vytvoříme vhodné makro, bude možné výpisy podle potřeby vypínat. V následující ukázce je pro vypínání či zapínání makra debug použit symbol NDEBUG, takže makro bude fungovat podobně jako assert. Příklad lze samozřejmě upravit a rozšířit, takže například vytvoříte různé skupiny maker pro výpisy, které půjdou vypnout podle potřeby (všechny/vybrané/žádné skupiny). Nebojte se experimentovat a vyzkoušejte si to.

#ifdef NDEBUG

#define debug(format, ...) {}

#else

#define debug(format, ...) \
  printf("%s, %s, %d: ", __FILE__, __func__, __LINE__); \
  printf(format, ## __VA_ARGS__)

#endif


// ukázka použití
int main(int argc, char **argv)
{
  debug("počet parametrů = %d", argc);
  ...
}
Makro pro ladící výpisy. Makra s proměnným počtem parametrů, stejně jako proměnná __func__ a makro __VA_ARGS__ jsou dostupná jen v překladačích, které znají normu ISO C99. Pokud nevíte, co znamenají symboly __FILE__, či __LINE__, zkuste jejich význam najít na internetu nebo v manuálových či info stránkách.

Ačkoli instrumentace poskytuje množství výhod, nelze ji použít vždy. Nelze ji použít v situacích, kdy by kontrolní tisky samy měly vliv na funkčnost programu. Problémy může působit například u některých procesů komunikujících přes standardní výstup (zde ale lze tisknout na stderr). Někdy může působit problémy i to, že tisk na obrazovku výrazně zpomaluje běh programu, takže se některé zákeřné chyby projeví až v okamžiku, kdy jsou kontrolní výpisy vypnuty. Dá se ovšem říci, že v 90% programů instrumentace nebude činit žádné problémy a umožní najít množství chyb.

Instrumentace ovšem principiálně nemůže příliš pomoci při hledání chyb při práci s ukazateli. Pokud si vypíšete na výstup hodnotu adresy, moc vám to neřekne. Pokud se pokusíte při výpisu dereferencovat chybně nastavený ukazatel, program pravděpodobně havaruje. V těchto případech může instrumentace někdy pomoci lokalizovat chybu, ale pro její skutečné odhalení sáhněte spíše po debuggeru nebo zkuste valgrind.

Instrumentace také nepomůže při hledání paměťových úniků, tedy situací, kdy program dynamicky alokuje data, ale už je neuvolní. V těchto situacích pomůže také spíše valgrind.

Instrumentace programů je dobrý doplněk pro hledání chyb, ale nelze se spoléhat pouze na něj. Některé chyby z principu odhalit nepomůže. Někdy může také vadit zmenšení přehlednosti výsledného kódu.