7. týždeň

Debugging

Základy práce s nástrojom cgdb, ladenie programov, polia, operátor sizeof

O čom je lab

V rámci tohto cvičenia sa naučíte svoje programy ladiť - debugovať pomocou nástroja cgdb, ktorý predstavuje nadstavbu nad nástrojom gdb. Ladenie programov patrí medzi základné zručnosti každého programátora a vie Vám značne pomôcť objasniť správanie programu počas jeho vykonávania. Ak si ladenie programov osvojíte, už nebudete potrebovať pri testovaní programov pomocné výpisy na obrazovku.

Ciele

  1. Naučiť sa základy práce s nástrojom cgdb .
  2. Rozumieť termínom a činnostiam súvisiacimi s procesom ladenia programov.
  3. Osvojiť si prácu s poliami čísel.
  4. Zoznámiť sa s operátorom sizeof() .

Postup

Krok 1: Linear Search: The Reconstruction

Každý programátor nejako začínal. Medzi začiatky mnohých programátorov patria rôzne algoritmy. Pozrite sa na nasledujúci fragment kódu, ktorý sa snaží o implementáciu lineárneho vyhľadávania. A ako to býva - na prvýkrát to fungovať nebude.

Vašou úlohou bude v tomto kroku opraviť všetky nedostatky tejto implementácie a ukázať, prečo je dobré absolvovať kurz Základy algoritmizácie a programovania.

Úloha 1.1

Stiahnite si súbor linear.c alebo vytvorte nový a prekopírujte si do neho nasledovný kód s lineárnym vyhľadávaním:

#include <stdio.h>

int search(const int[], const int);

int main(){
    int items[] = { 1, 5, 2, 3, 6, 8, 9, 7 };

    printf("Enter item to find: ");
    int find;
    scanf("%d", &find);

    int position = search(items, find);

    printf("Position of %d is %d\n", find, position);

    return 0;
}

int search(const int items[], const int find){
    int idx = 0;
    while(find != items[idx] || idx < sizeof(items)){
        idx++;
    }

    return idx;
}

Úloha 1.2

Preložte program tak, aby ho bolo možné načítať v nástroji cgdb.

Pri preklade potrebujete použiť parameter -g, ktorý vo výslednej preloženej binárke vytvorí informácie pre ladenie v natívnom formáte operačného systému (stabs, COFF, XCOFF, alebo DWARF 2). Tieto informácie vie následne prečítať debugger gdb, a teda aj cgdb.

Parameter -g môžete použiť priamo z príkazového riadku, ak budete prekladať v tvare:

gcc -std=c11 -Wall -Werror -g linear.c -lm -o linear

Rovnako tak môžete tento parameter vložiť do premennej prostredia CFLAGS, čím zabezpečíte používanie tohto parametra aj v prípade prekladu pomocou príkazu make. Overte si preto nastavenie tejto premennej v súbore ~/.bashrc (alebo ~/.profile - v závislosti od toho, ako spúšťate interpreter príkazov bash).

V prípade, že prepínač -g vo Vašej premennej prostredia CFLAGS chýba, dopíšte ho tam (odhláste sa a príhláste sa). Môžete však spraviť aj dočasnú úpravu premennej prostredia CFLAGS zadaním príkazu (úprava bude platná, kým nevypnete príkazový riadok):

export CFLAGS="$CFLAGS -g"

Poznámka

V prípade, že používate nami poskytnutý virtuálny stroj alebo server, prepínač -g sa už nachádza v premennej prostredia CFLAGS.

Úloha 1.3

Opravte chybu s operátorom sizeof().

Po preložení programu by malo dôjsť k nasledujúcej chybe (Avšak je možné, že staršie verzie prekladača túto chybu vôbec nezaznamenajú):

linear.c: In function ‘search’:
linear.c:21:45: error: ‘sizeof’ on array function parameter ‘items’ will return size of ‘const int *’ [-Werror=sizeof-array-argument]
     while(find != items[idx] || idx < sizeof(items)){
                                             ^
linear.c:19:22: note: declared here
 int search(const int items[], const int find){
                      ^~~~~
cc1: all warnings being treated as errors

Úloha 1.4

Pomocou nástroja cgdb identifikujte ďalšie chyby v uvedenej implementácii lineárneho vyhľadávania a opravte ich.

Po preložení programu s parametrom -g program v nástroji cgdb otvoríte príkazom (linear je názov Vami preloženého programu):

cgdb linear

Intro: stlačte ENTER pre pokračovanie, ak vidíte toto okno
Obr. 1: Intro: stlačte ENTER pre pokračovanie, ak vidíte toto okno

Nástroj cgdb po spustení
Obr. 2: Nástroj cgdb po spustení

  • Po spustení programu je obrazovka rozdelená na dve časti:
    • Okno so zdrojovým kódom (vrchná časť obrazovky)
    • GDB okno (spodná časť obrazovky)
  • Nástroj je orientovaný na používateľov editora ViM, takže niektoré klávesové skratky a spôsob ovládania im budú dôverne známe
  • Ak sa chcete dostať do okna so zdrojovým kódom, stlačte klávesu ESC. Tým sa dostanete aj do tzv. CGDB režimu. Ak sa naopak chcete dostať späť do GDB okna, stlačte klávesu i. Tým sa dostanete aj do tzv. GDB režimu.
  • Pokiaľ Vám nevyhovuje rozloženie okien a hlavne ich veľkosť, z CGDB režimu môžete meniť veľkosť okien pomocou kláves - a =.
  • V režime CGDB sa viete pohybovať po zdrojovom kóde kurzorovými klávesami (šípkami), prípadne klávesami pre navigáciu po súbore známymi z editora Vim.
  • Pokiaľ chcete na nejakom riadku pridať bod prerušenia (breakpoint), stlačte na ňom klávesu SPACE. Opätovným stlačením tejto klávesy daný breakpoint odstránite.
  • Program spustíte z režimu CGDB stlačením klávesy F5. Pokiaľ máte na nejakom riadku nastavený breakpoint, vykonávanie sa na ňom zastaví. V tomto momente môžete program krokovať (vykonávať jednotlivé riadky postupne) a sledovať stav jednotlivých premenných.
  • Ak Váš program pracuje so štandardným vstupom a výstupom, potrebujete v nástroji cgdb zapnúť tzv. TTY pohľad. Ten zapnete a vypnete z CGDB režimu pomocou klávesy T. Pokiaľ teda potrebujete niečo zadať z klávesnice alebo vypísať na obrazovku, budete to robiť cez pohľad TTY.

TTY okno pre prácu so štandardným vstupom a výstupom
Obr. 3: TTY okno pre prácu so štandardným vstupom a výstupom

  • Ak chcete vykonať v programe jeden krok, stlačte klávesu F8. V ktoromkoľvek momente sa môžete prepnúť do okna gdb a zobraziť si obsah premennej dostupnej v danom kontexte (rozsahu) pomocou príkazu (VARNAME je názov premennej, ktorej obsah si chcete zobraziť):
print VARNAME
  • Ak sa Vám nechce neustále zobrazovať obsah premennej pomocou príkazu print, je možné vytvoriť zoznam premenných, ktoré sa budú zobrazovať pri každom zastavení programu. To docielite pomocou príkazu (VARNAME je názov premennej, ktorej obsah si chcete zobraziť):
display VARNAME
  • Každej takto zobrazovanej premennej sa priradí identifikačné číslo (VARNUMBER), pomocou ktorého môžete neskôr premennú z tohto zoznamu vyradiť príkazom:
undisplay VARNUMBER
  • Ak sa program zastavil na breakpoint-e a potrebovali by ste program znovu rozbehnúť, môžete stlačiť klávesu F6. Vykonávanie programu sa zastaví opäť, keď narazí na ľubovoľný breakpoint.
  • Debugger môžete mať otvorený v samostatnom okne a v druhom môžete aktualizovať program. Po jeho preložení a opätovnom spustení v programe cgdb dôjde k jeho aktualizácii. Ak však chcete program aktualizovať ručne ešte pred jeho spustením, v režime GDB napíšte príkaz update.

Prehľad vybraných príkazov a klávesových skratiek nástroja cgdb sa nachádza v nasledujúcej tabuľke. Pre kompletný prehľad príkazov v režime cgdb prejdite do manuálu programu cgdb.

CGDB Mode GDB Mode Description
quit ukončenie programu
ESC prechod do režimu CGDB (okna so zdrojovým kódom)
i prechod do režimu GDB (okna s GDB)
I prechod do režimu TTY (okna s TTY)
SPACE pridanie/odstránenie breakpoint-u na danom riadku
F5 run spustenie programu
F6 continue znova spustí pozastavený program
F8 next vykonanie jedného kroku (príkazu) programu
print VARNAME zobrazenie obsahu premennej VARNAME
display VARNAME automatické zobrazenie obsahu premennej VARNAME pri každom zastavení programu
undisplay VARNUMBER zrušenie automatického zobrazenia obsahu premennej s číslom VARNUMBER
update aktualizovanie verzie nahratého programu
- zmenšenie okna so zdrojovým kódom
= zväčšenie okna so zdrojovým kódom
T zapne/vypne TTY pohľad

Doplňujúce zdroje

  1. CGDB Manuál
  2. Domovská stránka nástroja CGDB
  3. Domovská stránka nástroja GDB
  4. Linear search
  5. Operátor sizeof(): c-reference - Queries size of the object or type. Used when actual size of the object must be known.
  6. Ako zistiť veľkosť poľa

Video