Bonjour et bienvenue.
Dans ce cours, j'aimerais parler un peu de la pile d'appels, de ce qu'elle est exactement et de la façon dont
vous pouvez la lire pour vous aider à déboguer votre programme.
Une trace de pile, qui correspond essentiellement à la pile d'appels, est générée chaque fois que votre application se bloque
en raison d'une erreur fatale.
La raison pour laquelle le terme "pile" est utilisé est qu'il fait référence à une structure de données courante en programmation.
La pile est une structure de données connue sous le nom de LIFO, last in, first out, et c'est ainsi que les données sont
stockées.
Le dernier élément de données ajouté est le premier que vous récupérez.
C'est un peu comme si vous mangiez une pile de crêpes, la première crêpe est celle du bas que
vous ajoutez.
La dernière crêpe se trouve au sommet.
Lorsque vous allez les manger, vous mangez le dernier qui a été ajouté.
La trace de pile est donc très utile lorsque votre programme se bloque, car elle contient des informations qui vous aident
à le déboguer.
Une trace de pile montre donc une liste des appels de fonction qui ont conduit à l'erreur.
Dans un programme, lorsque vous appelez votre fonction principale, c'est le point d'entrée.
La fonction principale va appeler d'autres fonctions.
Ces fonctions vont appeler d'autres fonctions et toutes les fonctions qui seront mises en œuvre ou appelées
seront placées sur la pile.
Ainsi, lorsqu'un programme se bloque, la pile d'appels vous indique la dernière fonction qui a été
invoquée et la ligne de code spécifique qui a provoqué l'erreur.
La pile d'appels contient donc de nombreuses informations utiles.
Elle comprendra le nom du fichier et les numéros de ligne du code à l'origine de l'exception ou de
l'erreur fatale.
Le sommet de la pile contient le dernier appel qui a provoqué l'erreur et il peut y avoir des appels imbriqués.
Le bas de la pile contient le premier appel qui a déclenché la chaîne d'appels pour appeler l'erreur.
Ainsi, si vous êtes habituellement en C, ce sera au niveau de la routine main, vous invoquez la main, la main invoque une autre fonction,
qui invoque une autre fonction, et ainsi de suite.
Et la dernière ligne est détaillée.
C'est très, très utile quand une application se plante après l'autre.
Ainsi, lorsqu'un programme C se plante, il peut générer une erreur de segmentation, ce qui ne vous donne pas beaucoup d'informations.
Cela signifie simplement que quelque chose de grave s'est produit.
Cela générera également un fichier de base.
Vous pouvez analyser le fichier core qui contient la pile d'appels, ce qui vous indiquera la ligne
de code exacte qui est à l'origine du problème.
Vous devez donc trouver l'appel dans votre application qui est à l'origine du plantage.
La pile d'appels est probablement le meilleur moyen d'y parvenir.
Et il n'est pas toujours nécessaire de consulter ce fichier central.
Vous pouvez également analyser la pile d'appels en utilisant GDB avec un débogueur.
Et je veux vous montrer à quoi cela ressemble.
Le programmeur peut également extraire la trace de la pile à tout moment.
Ainsi, si vous attrapez une erreur ou si vous reconnaissez qu'une erreur fatale peut se produire, vous pouvez vider
la pile d'appels pour voir ce qui se passe.
Si vous ne savez pas quand l'erreur va se produire, vous pouvez toujours extraire la
pile d'appels pour voir les traces actuelles qui ont conduit à un appel particulier.
Lorsque vous utilisez GDB, la pile d'appels ressemble à ceci.
Vous pouvez accéder à la pile d'appels via le menu lorsque vous lancez le débogueur dans GDB et je vais vous montrer
comment faire, mais voici à quoi elle ressemble et ce que vous verrez ici, c'est qu'elle contient un numéro, une
adresse et ensuite la fonction.
Cette pile d'appels particulière comporte un grand nombre d'appels différents, ce qui signifie qu'elle a dû effectuer un grand nombre d'imbrications
et d'appels de fonctions différentes.
Mais tout en bas de la pile, à la ligne 22, il est indiqué GTK main.
Cela signifie que le.
Cela signifie qu'il a probablement exécuté la fonction principale.
Puis, à la ligne 21, on dirait qu'il s'est exécuté.
Peut-être qu'une déclaration indique l'exécution de la boucle principale.
Ensuite, on dirait qu'on a appelé une fonction appelée G main context iterate.
Et à l'intérieur de cette fonction, il y avait chaque fois un autre appel à une fonction de distribution du contexte
principal de l'IAG.
Il y avait donc une fonction iterate, puis une fonction dispatch, et les points d'interrogation à la ligne 18 signifient
qu'il n'y a pas d'informations de débogage.
Elle ne sait pas ce qui s'y est passé.
C'est pourquoi, lorsque vous créez votre programme, vous pouvez soit le créer pour le publier, soit le créer avec
des informations de débogage.
Lorsque vous le construisez avec des informations de débogage, il contient des informations supplémentaires lors de la compilation, de sorte que
lorsque vous l'exécutez, vous pouvez consulter les piles d'appels.
Lorsque vous le publiez, construisez quelque chose pour le publier.
L'exécutable est beaucoup plus petit et peut ne pas contenir ces informations.
Il peut contenir davantage de points d'interrogation.
Mais cela vous dira aussi si vous avez invoqué des bibliothèques, des programmes supplémentaires, il les appellera et vous indiquera
la pile d'appels à partir de là.
Mais ce que cela montre, encore une fois, c'est que les différents événements imbriqués pour l'appel tout en
haut sont importants, parce qu'ils indiquent ce qui a causé le crash.
Il semble donc que dans cette pile d'appels particulière, le rafraîchissement interne ait causé un problème.
Et vous pouvez voir que de la ligne 22 à la ligne zéro, il y a beaucoup d'invocations différentes de différents
codes.
Mais l'éventuel plantage du programme à la ligne zéro appelle les piles.
Vous pouvez également examiner les piles d'appels pendant l'exécution du programme afin d'obtenir des informations qui vous permettront de remonter jusqu'à
la source.
Ainsi, si vous placez un point d'arrêt à l'intérieur d'une fonction, vous déboguez, vous exécutez le débogueur sur cette fonction.
Le débogueur va s'arrêter à ce point d'arrêt.
Vous pouvez alors faire apparaître la pile d'appels et elle vous indiquera comment vous êtes arrivé à cette ligne de code.
Cette fonction a été invoquée avant cette fonction.
Et là encore, on commence généralement par la fonction principale.
Vous pouvez également passer à différents cadres si vous êtes familier avec la pile, le concept et la façon
dont elle est en mémoire, vous pouvez regarder différents cadres, mais c'est un outil très utile pour trouver principalement
des crashs en C, et c'est très facile à lire.
Si vous ne regardez que le sommet et que vous ne comprenez pas grand-chose à la pile d'appels,
vous pouvez regarder le sommet et dire : "Oh, c'est une source, c'est une ligne de code qui a causé le crash".
Voici un bel exemple que j'ai trouvé sur le web.
Excma.
Edu.
Cela illustre des exemples de piles d'appels de fonctions.
Si nous regardons un exemple de code, nous verrons qu'il s'agit d'un code simple.
Les calculs n'ont pas vraiment d'importance.
Nous appelons simplement quelques fonctions.
Nous avons donc cette fonction mogrify et cette fonction truly half et le main va appeler une fonction mogrify, puis
il va appeler truly half et ensuite il va mogrify. Nous pouvons donc illustrer la pile d'appels
et ce à quoi elle ressemble lors de ces appels en plaçant un simple point d'arrêt dans le main et en regardant la pile
d'appels au fur et à mesure que nous progressons et que nous effectuons des appels.
Là encore, nous allons nous familiariser avec les points d'arrêt et les informations de ce type.
Mais je veux juste montrer rapidement la pile d'appels et nous donnerons un exemple plus détaillé de la
pile d'appels plus tard.
J'ai donc placé un point d'arrêt.
Je peux aller de l'avant et construire et compiler ceci et je peux démarrer le débogueur et nous atteindrons ce point d'arrêt.
Ce que vous remarquerez maintenant, c'est que vous pouvez voir tous les menus du débogueur ici à droite en bas,
et vous verrez la pile d'appels.
Agrandissons un peu le champ d'application.
Mais lorsqu'il s'arrête à la ligne 14, il n'y a plus que quelques instructions d'affectation et vous verrez
que la pile d'appels indique main.
Si nous passons à la ligne suivante, nous pouvons voir qu'elle va jusqu'à la ligne 15 avant d'appeler
Mogrify, n'est-ce pas ?
Ainsi, la pile d'appels reste avec Main.
Si nous entrons dans le système, vous verrez que la pile d'appels affiche Mogrify.
Nous sommes donc à l'intérieur de cette fonction.
Nous pouvons passer outre.
Il exécute donc la première ligne et renvoie ensuite temp.
Il reste dans cette fonction et retourne ensuite à l'endroit où il imprime F à la ligne 16, vous voyez comment la pile
d'appels change.
Nous passons ensuite à la ligne 18, nous appelons la pile dans main et nous entrons dans la moitié de la fonction.
Vous voyez maintenant que la pile d'appels change et qu'elle montre vraiment que la moitié de la fonction en haut est toujours
la fonction qui a été appelée en dernier.
Une fois de plus, nous faisons un pas en avant et nous constatons que nous sommes toujours dans la vraie moitié.
Nous retournons à Main, nous imprimons quelque chose à la ligne 19, nous allons à la ligne 21.
Nous sautons à nouveau dans la fonction modifier, que vous voyez à nouveau sur la pile d'appels, nous sautons, nous sautons et finalement
nous imprimons le résultat final à la ligne 23 et nous quittons le programme.
Mais la pile d'appels nous montre à nouveau l'ordre des fonctions qui sont invoquées d'une fonction à l'autre.
Si vous avez des fonctions imbriquées, cela peut devenir de plus en plus compliqué.
L'avantage de la pile d'appels est que si une ligne de code se plante, disons à la ligne quatre, vous aurez une pile d'appels
qui contiendra tout en haut l'endroit où la ligne s'est plantée.
Ainsi, en parcourant la pile d'appels, vous pouvez voir quelle est la dernière ligne de code qui a été invoquée,
ce qui vous permettra de savoir quelle ligne de code s'est écrasée.
Mais vous voudrez utiliser cet outil lorsque votre programme se bloquera.
Nous vous remercions.