Qt Creator : guide d'utilisation du débogueur

Le but de ce document est de vous montrer comment utiliser le dévermineur (« debugger ») intégré à QtCreator. Les dévermineurs sont des outils vous permettant de traquer les problèmes d’exécution dans un programme. Leur utilisation est quasiment indispensable dans le cadre de la réalisation de projets de programmation.

Commencez par créer un projet simple selon les indications du document « Qt Creator : guide d’utilisation de base » (section 1). Nommez ce projet test_debug par exemple et copiez les instructions suivantes dans le fichier main.cpp :

int main()
{
  int a, b;
  a = 1024;
  b = a*a*a-1;
  a = 2*b;
  b = a+1;
  a = b+1;
  b = 4*b;
  a = 2*a;
  b = b/a;
  cout << b << endl;
  return 0;
}
Code pour l’essai du debugger.

Lancez la compilation au moyen du petit marteau en bas à gauche, puis l’exécution au moyen de la petite flèche verte. Ouvrez l’onglet Application output (au milieu en bas), vous devriez constater que le programme s’est terminé de façon anormale :
Crash du programme

Le dévermineur (« Debugger ») va vous permettre de localiser l’erreur dans le programme et d’en déterminer la cause.

Condition préalable au lancement du dévermineur

Pour que le dévermineur puisse fonctionner de façon optimale, il faut que le compilateur ait été lancé avec l’option -g.

Ce sera le cas dans votre projet simple, si vous choisissez « Debug » comme cible (ce qui est le cas par défaut) :
Choisir la cible « Debug » (choix par défaut)

Dans des projets compilables avec Cmake (comme celui qui est proposé dans notre cours-projet « Projet de programmation en C++ »), il faut que le fichier CMakeList.txt contienne la ligne :

set(CMAKE_BUILD_TYPE Debug)

Lancement du dévermineur

Pour lancer l’exécution du programme au moyen du dévermineur, cliquez sur la flèche verte avec un petit insecte (« bug ») dessus (cf fig. 2). Une fenêtre d’alerte apparaît avec un message d’erreur (« Arithmetic exception »). Fermez cette fenêtre en cliquant sur le bouton OK. Vous pouvez voir que la ligne de code ayant provoqué l’erreur est désignée par une flèche dans le code source (cf fig. 2).

Crash du programme sous dévermineur

Affichage de la valeur des variables

Un premier pas vers l’identification des causes de l’erreur consiste à examiner la valeur des variables impliquées dans la ligne fautive. Ces valeurs sont visibles dans la fenêtre qui apparaît à droite du code source ou encore simplement en plaçant la souris sur les variables concernées dans le code source (cf fig. 3).

Affichage de variables dans le dévermineur

Vous devez pouvoir ainsi observer les valeurs a=0 et b=-4. Ce sont les valeurs des variables au moment où l’erreur a été détectée. La cause de l’erreur devient évidente : la division par a=0.

Dans la suite, vous allez exécuter le programme pas-à-pas, pour comprendre à quel moment les résultats des calculs deviennent aberrants.

Exécution d’un programme pas à pas

Arrêtez le programme en cliquant sur le petit carré rouge avec l’insecte dessus sous l’onglet « Debugger » (cf fig. 3).

Pour exécuter le programme pas-à-pas, il faut commencer par mettre un point d’arrêt (« breakpoint ») à l’endroit où l’on veut commencer l’observation. Dans cet exemple, on va observer le déroulement du programme depuis le début, c.-à-d. depuis la première ligne du main(). Cliquez sur cette ligne, dans la marge où apparaissent les numéro de lignes (à gauche du numéro), avec le bouton droit de la souris. Un point d’arrêt apparaît sur la ligne sélectionnée, symbolisé par un petit cercle rouge avec un petit sablier dessus (cf fig. 4).

Point d’arrêt dans le dévermineur

Lancez alors à nouveau le programme (flèche verte avec l’insecte). Il s’arrête au premier point d’arrêt. La flèche jaune dans la zone de programme indique la prochaine ligne qui doit être exécutée (cf fig. 5).

Arrêt du dévermineur sur un point d’arrêt
  • pour exécuter une ligne à la fois, cliquez sur le boutons « step over », (voir les bouton encadrés en rouge dans la figure 5) ;

  • si l’instruction est un appel de fonction, il est possible d’exécuter pas-à-pas le corps de la fonction en utilisant le bouton « step into » (ce n’est pas utile dans cet exemple) ;

  • pour continuer le programme jusqu’à la fin, sans s’arrêter à chaque ligne, cliquez sur bouton « continue ».

Exécutez le programme pas-à-pas en cliquant sur « step over », et observez l’évolution des valeurs des variables. Ce processus doit vous amener à comprendre à quel moment les valeurs deviennent aberrantes.

Le but de ce petit guide est de vous faire exécuter un programme pas-à-pas en suivant l’évolution des variables, et non de comprendre pourquoi le programme se comporte bizarrement.

Voici cependant, à titre documentaire, l’explication succincte de son comportement :

Le programme a un comportement anormal à partir de la ligne

a = b+1

En effet, à ce moment-là, la valeur de b est la plus grande valeur possible pour une variable de type int. En effet le type int n’est pas un vrai type entier au sens mathématique du terme. Les variables de ce type sont en fait bornées dans l’intervalle [-MAX_INT - 1, MAX_INT].

Pour l’ordinateur, si b=MAX_INT, alors b+1 = -MAX_INT - 1 !!!

Et si a=-MAX_INT - 1, alors 2*a = 0 !!!

Dès que l’on dépasse les capacités de représentation, les résultats donnent des valeurs aberrantes du point de vue de l’arithmétique usuelle !

Le tout est de le savoir !

Pile des appels (« Call stack »)

Dans des programmes plus complexes, il est intéressant d’exploiter la piles des appels de fonctions; c.-à-d. la suite des appels de fonctions qui se sont exécutées avant un point d’arrêt (ou un « crash »). Il est possible de remonter dans cette pile simplement en cliquant sur ses lignes. Ceci permet d’examiner à chaque étape du processus, quelles valeurs ont pris les différentes variables impliquées comme illustré en figure 6.

Pile des appels
Last modified: Tuesday, 28 February 2023, 17:38