Compilar per depurar
gdb necessita que el compilador hi deixi informació extra (noms de variables, línies del codi font) amb l'opció -g.
gcc -g programa.c -o programa gdb ./programa
Punts de ruptura
Un punt de ruptura (breakpoint) atura l'execució just abans d'una línia o funció concreta, perquè puguis inspeccionar l'estat del programa en aquell moment.
(gdb) break compta_elements (gdb) run
break pot rebre un nom de funció o un número de línia. run comença l'execució, que s'aturarà automàticament quan hi arribi.
Avançar i inspeccionar
| Comanda | Fa |
|---|---|
next (n) | executa la línia actual i avança a la següent, sense entrar dins de cap funció que es cridi |
step (s) | igual, però SÍ entra dins de la funció cridada |
print x (p x) | mostra el valor actual de la variable x |
continue (c) | reprèn l'execució fins al pròxim punt de ruptura, o fins que el programa acabi |
Ho veuràs tot en marxa a la pestanya d'execució: una sessió real de gdb, aturant un programa amb un bug de debò per trobar-lo.
Taula de referència
| Comanda | Fa |
|---|---|
break <línia/funció> | posa un punt de ruptura |
run | comença l'execució |
next / step | avança una línia (sense / amb entrar a funcions) |
print <expressió> | mostra un valor |
list | mostra el codi font al voltant de la línia actual |
continue | reprèn l'execució |
quit | surt de gdb |
Una sessió real de gdb, pas a pas
Aquestes dues sessions són transcripcions de gdb executant-se de debò — inclosos els valors exactes que va mostrar.
Sessions de gdb
Codi
Variables
| Nom | Valor |
|---|
Sessió de gdb
Problemes per resoldre
Sense solució: compila cada programa amb gcc -g programa.c -o programa i fes servir gdb de debò per trobar el bug. Les pistes són plegades perquè les obris només si les necessites.
1. Un bucle que no avança
Aquest programa s'hauria de quedar penjat (bucle infinit):
int i = 0;
while (i < 5) {
printf("%d\n", i);
}
Fes servir gdb per confirmar per què i mai arriba a 5.
Pistes
Posa un break a la línia del printf, fes run, i després diversos next seguits de print i cada cop.
Veuràs que i val sempre 0: li falta un i++; dins del bucle.
2. Un punt i coma de més
Aquesta funció hauria de calcular base elevat a exp (multiplicant resultat per base, exp vegades), però potencia(2, 5) dona 2 en lloc de 32:
int potencia(int base, int exp) {
int i, resultat = 1;
for (i = 0; i < exp; i++);
resultat = resultat * base;
return resultat;
}
Troba el bug amb gdb.
Pistes
Posa un break potencia, fes run i després next diverses vegades seguint la línia activa: veuràs que resultat només canvia un cop, encara que el bucle hauria de fer 5 voltes.
Mira bé el final de la línia del for: hi ha un punt i coma (;) que el tanca immediatament, deixant-lo sense cos. La línia següent (resultat = resultat * base;) ja no en forma part: s'executa només una vegada, després que el bucle hagi acabat. (De fet, gcc -Wall ja t'hauria avisat d'això amb un avís de "misleading indentation".)
3. Una variable sense inicialitzar
Aquest programa hauria de sumar 1, 2 i 3, però dona un resultat diferent cada cop que s'executa:
int total;
total = total + 1;
total = total + 2;
total = total + 3;
printf("%d\n", total);
Pistes
Posa un break a la primera línia i fes print total abans de res més. Ja veuràs que no val 0: mai s'ha inicialitzat, així que conté el que hi hagués abans en aquella posició de memòria.
Exercicis d'autoavaluació
Aquests es generen amb valors nous a l'atzar i tenen solució comprovable.
Un cop el programa s'atura al punt de ruptura, quin valor mostrarà aquest print?