Debugging

Programele pot să nu meargă din mai multe motive. Pagina aceasta prezintă câteva abordări pe care să le urmați pentru a face debugging atunci când programele voastre nu funcționează. Lista nu este exhaustivă, ci doar prezintă câteva erori frecvente și moduri în care ați putea să le rezolvați.

Erori de compilare

Dacă programul vostru nu este scris corect din punct de vedere sintactic, atunci acesta va da erori la compilare.

gcc generează un excutabil doar dacă NU au existat erori de compilare. Dacă generează output, înseamnă că există probleme. Trebuie să vă asigurați întotdeauna că gcc nu a generat niciun output, pentru a fi siguri că aveți un executabil nou generat.

Uneori gcc generează erori și astfel nu se generează fișierul executabil dorit. Dacă totuși există un executabil, înseamnă că este cel creat înainte ca compilarea să înceapă să genereze erori. Aceasta este o greșeală frecventă.

Asigurați-vă întotdeauna de faptul că gcc nu produce niciun output.

Warning-uri de compilare

gcc poate identifica unele probleme, dar care nu generează erori, ci warning-uri. În cazul acesta, compilarea reușește și generează un executabil nou.

Warning-urile nu sunt erori pentru că sunt cazuri în care programatorul consecințele acestora și pot face parte din rezolvarea voită a programului.

Pentru a forța compilatorul să afișeze toate warning-urile folosiți paramentrul -Wall. Exemplu:

gcc -Wall ex1.c -o exe

În cadrul cursului de programare nu vom avea niciodată nevoie de construcții ce sunt ok chiar dacă compilatorul arată warning-uri. De aceea vă încurajăm să scăpați întotdeauna de ele.

Warning-urile pot duce la rezultate eronate. Exemplu de posibile warning-uri:

  • folosirea unei variabile neinițializate
  • atribuirea de număr cu semn unui întreg fără semn
  • cast-uri de la int la char (deci cu diminuare de spațiu)
  • atribuirea de pointeri la variabile numerice
  • etc.

Toate aceste warning-uri pot face ca rezultatul calculat să nu fie cel dorit.
Amintiți-vă de exemplele din laboratorul 02.

Segmentation fault / stack smashing detected

Erorile de genul aceasta înseamnă, pe scurt, că undeva faceți un acces nevalid de memorie. Cel mai frecvent, cauza poate să fie una din următoarele:

  • accesați printr-un indice un element într-un vector nealocat (exemplu: dacă vectorul a fost declarat int v[100], iar voi accesați v[100] sau chiar cu un indice mai mare sau cu unul negativ)
  • folosiți o funcție recursivă care nu are condiție de oprire, sau condiția acesteia nu funcționează corect sau nu acoperă cazul din testul rulat
  • apelați funcția free pe o zonă de memorie nealocată sau pe una care a fost eliberată anterior
  • etc.

Pentru a identifica problemele în cazul acesta puteți să folosiți printf stylel debugging, cu mențiunea de a fi atenți cum folosiți afișarea.

Pentru a identifica mai ușor punctul în care se întâmplă eroarea recomandăm folosirea gdb sau valgrind.

Pentru ambele tool-uri vom avea nevoie să adăugăm la compilare flag-ul -g pentru a activa simbolurile de debugging. Astfel:

gcc -g -Wall ex1.c -o exe 

Spre exemplu, o rulare simplă cu valgrind ar arăta așa (dacă programul are argumente le adăugați în continuare):

valgrind ./exe

Urmăriți output-ul generat. Ar trebui să vă spună exact linia pe care se întâmplă eroarea și cauza acesteia. Mai multe detalii în tutoriale.

Pun printf dar nu apare, iar apoi crapă programul

printf este o funcție care înainte de a afișa datele pe ecran le scrie într-un buffer intern pe care-l afișează pe ecran doar în următoarele cazuri:

  • se umple bufferul (este destul de mare!)
  • este forțată afișarea (folosind apelul: fflush(stdout);)
  • este afișat caracterul newline (adică '\n')

Dacă voi scrieți ceva în buffer (exemplu: printf(“Hello!”);) iar după aceea apare o eroare de genul segmentation fault, nu înseamnă că programul vostru nu a ajuns să execute instrucțiunea printf. Înseamnă doar că buffer-ul respectiv nu a ajuns să fie afișat pe ecran.

Recomandăm să folosiți caracterul newline întotdeauna pentru debugging. Astfel:

printf("Hello\n");

Ieșirea standard de eroare nu bufferează datele, ci le afișează imediat pe ecran. Puteți folosi acest flux, dacă doriți, astfel:

printf("Hello");

devine:

fprintf(stderr, "Hello");

Other

Dacă rezultatul nu este cel așteptat, înseamnă că undeva s-a produs o eroare în cod. De multe ori poate fi un indice pus prost, sau o relație de inegalitate greșită. Pentru aceste cazuri, recomandăm să faceți verificări în diversele puncte ale programului.

Puteți fie să folosiți un debugger pentru a verifica ce valori iau diversele variabile pe parcursul execuției programului, fie să folosiți așa numitul printf style debugging. Pentru aceasta încercați să afișați valorile în diverse puncte ale programului pentru a identifica zona în care rezultatul se strică.

Recomandăm să începeți să afișați diversele valori esențiale de sus în jos. Cel mai probabil primul pas de verificat este imediat după citirea datelor de intrare. Asigurați-vă că ati citit valorile corect. Este o greșeală des întâlnită, mai ales printre începători, pentru că folosesc funcția scanf cu diverse formate fără să înțeleagă pe deplin ce se întâmplă.

După ce ați verificat că ați citit corect datele, afișați valorile esențiale după fiecare secvență care le modifică în programul vostru. Nu puneți printf peste tot încă de la început, abordați incremental. Pentru bucle recomandăm să afișați indicele pentru fiecare iterație alături de alte valori pentru a putea urmări cum evoluează acestea.

programare/debugging.txt · Last modified: 2016/10/31 08:57 by laura.vasilescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0