[? DAN ARMADARAS:?] Salut, Je suis [? Dan Armadaras?]. Aujourd'hui, nous allons être à la recherche au débogage. Non seulement allons-nous parler de certaines techniques, mais aussi nous allons regarder certaines des caractéristiques contenues au sein de l'IDE qui permettent CS50 de déboguer facilement un programme. Juste un exemple de quelque chose qui peut aller mal et il est en fait quelque chose que nous avons déjà vu avant. Dans ce cas, cela est un programme C qui accepte un nombre entier de l'utilisateur, la divise par deux, et fournit la sortie à l'utilisateur. Maintenant à partir de ce que nous avons vu plus tôt dans des conférences, nous savons que ce sera effectivement causer des types spécifiques de problèmes de division lorsque nous avons des numéros impairs. Plus précisément, nous allons simplement jetons quoi que ce soit après la virgule. Maintenant, nous savons que ce arrive à être le cas. Et si nous courons, nous pouvons confirmer nos soupçons, d'abord, par la compilation. Et puis, en courant et en entrer un nombre impair. Rien de nouveau. Mais cela est en fait un exemple d'un bug qui peut exister au sein d'un programme plus vaste cela devient plus difficile à traquer. Même si nous savons quel est le problème est, le véritable nœud de la question pourrait être d'essayer d'identifier spécifiquement où l'erreur se produit, identifier ce que ce problème est, puis fixer. Donc fournir cela comme un exemple de ce qui pourrait être quelque chose que nous savons déjà, mais peuvent être enterrés dans les autres éléments du code. Donc, l'ouverture de cette autre source fichier de code comme un exemple, ce problème est maintenant de division partie d'un programme plus vaste. Encore pourrait être un peu peu artificiel, et nous pourrait être en mesure de facilement identifier, en particulier puisque nous sommes en train de discuter de cette. Mais nous pouvons comprendre que cette problème peut exister sur une plus grande échelle. Si je compile cela et maintenant exécuter, entrez un nombre impair, nous pouvons voir que nous ne recevons pas précisément la sortie que nous avons prévu. Dans ce cas particulier, nous pourrions dire que nous vouloir compter tous les numéros de une à un nombre spécifique. Et nous pouvons voir que nous avoir une variété de questions ici si nous délivrer, tout simplement, 0 et 1 lorsque nous fournissons une entrée 5. Donc, nous savons déjà que il ya un problème ici. Mais nous ne savons pas précisément où cette question existe réellement. Maintenant l'un des moyens que nous pouvons essayer de résoudre ce problème est quelque chose que nous avons déjà été introduite à. Nous pouvons simplement l'utiliser sur une plus grande échelle. Sur la ligne 14, nous avons cette fonction printf, ce qui nous permet d'imprimer sur l'état de divers éléments d'information. Et ceci est quelque chose que vous devrait tirer parti de votre programme pour essayer de comprendre exactement ce qui est passe dans diverses lignes de code. Donc, même si ce ne est pas sortie finale que nous fait vouloir produire sur ce programme, nous avons encore pourrait avoir une certaine debug états où nous peut essayer de comprendre précisément ce que qui se passe à l'intérieur de notre code. Donc dans ce cas, je vais printf avec l'étiquette de débogage. Dans ce cas, cela est juste une chaîne de débogage que je suis jusqu'à la mise-de sorte qu'il devient très clair dans la sortie de mon code ce qu'il est que je veux montrer. Et sortie ici le nombre que nous avons calculé. Dans ce cas, je pourrais veulent savoir précisément ce qui se passe avant et après un certain calcul spécifique. Donc, je pourrais utiliser un printf avant et après cette ligne de code. Dans ce cas, je ne pouvais même rendre un peu plus clair en disant débogage avant et déboguer après tant que je ne me confonds pas avec plusieurs lignes qui semblent identiques. Maintenant, si nous recompiler et exécuter il, entrez un numéro comme cinq fois, nous pouvons voir que nous avons maintenant affichée avant et après et constatons que nous avons fait un pas clair division ou ayant clairement du nombre que nous voulons réellement faire. Or, dans ce cas, cela est pas vraiment un résultat clair. Il est pas vraiment un résultat clair que nous voulons sortir de ce programme particulier. Et cela est, à nouveau, un peu parvint. Mais, peut-être, l'une des choses qui nous pourrions faire si la spécification dit que nous voulons diviser par 2 et ajouter 1-- donc en d'autres termes, nous voulons arrondir up-- puis nous sachions que nous pourrions faire cette chose particulière, dans ce cas. Maintenant, ici, nous savons que nous serons en mesure d'ajouter 1 à notre nombre réduit de moitié. Disons recompiler et de confirmer que cette se comporte de la façon dont nous voulons. Nous pouvons voir que maintenant avant ayant, nous avons le numéro 5. Après avoir, nous avons le numéro 3, qui, selon notre cahier des charges, est ce que nous voulions faire. Mais si nous regardons le sortie ici, nous pouvons voir que nous pourrions avoir une autre bug tout à fait, qui est que nous commençons notre comptage de 0. Maintenant, encore une fois, ceci est quelque chose que nous avons vu dans le passé et nous pouvons corriger assez facilement. Mais dans ce cas, nous également eu l'avantage d'utiliser l'instruction printf directement à l'intérieur de la boucle for de savoir précisément où cette erreur se produisait. Donc déclarations sont printf très utile pour aider à déterminer où, précisément dans le code source, une erreur spécifique est en cours. Et il est aussi important de réaliser que, comme nous l'écriture de code, nous pourrions avoir des hypothèses sur l'état d'un programme. Ou nous pourrions avoir hypothèses sur ce que le cadre du programme est en fait correcte ou incorrecte lorsque plus tard que nous construisons sur ce programme et faire partie d'un complexe et vaste programme que nous nous rendons compte que certains aspects de qui est réellement buggy. Utilisation de printf peut vraiment aider affiner et d'identifier les régions d'un programme qui ne peut se comporter exactement de la manière que nous attendre, sur la base de nos hypothèses. Mais il ya d'autres outils disponibles, ainsi, qui nous permettent d'essayer de comprendre où une erreur se produit Et aussi, précisément, que les choses sont passe à l'intérieur du programme. Donc, en utilisant printf est très lorsque cela est utile que nous voulons d'identifier les domaines spécifiques de un programme qui possède quelques bugs. Mais il devient aussi pénible après un moment. Dans ce cas, cela est un programme relativement simple avec seulement une ou deux variables. Et il devient très facile pour nous de imprimer la valeur de ces variables dans le contexte plus large du programme. Mais nous pourrions avoir une autre programme qui a de nombreuses variables. Et il ne peut pas être tout à fait si facile à utiliser printf pour tenter d'évaluer ce qui se passe à chacune de ces variables que le programme est exécuté. Il ya un programme qui existe appelé un programme de débogage. Dans ce cas, celui que nous allons l'utilisation est le débogueur GNU, ou GDB, qui nous permet d'inspecter les internes fonctionnement d'un programme dans une beaucoup plus de façon détaillée. Nous pouvons en fait exécuter GDB de la ligne de commande ici en tapant simplement GDB et la commande que nous voulons pour déboguer. Dans ce cas, compter. Or, dans ce cas, nous pouvons voir qu'il nous amène à une invite qui dit GDB. Et nous pouvons réellement exécuter des commandes GDB pour commencer effectivement l'exécution de la programme, l'arrêter à certains points, évaluer les variables et inspecter les variables exister à l'état de programme à ce moment particulier, et ainsi de suite. Il offre beaucoup de puissance pour nous. Mais il se trouve que l'IDE CS50 aussi fournit une interface graphique ou un utilisateur Interface pour que GDB nous permet de faire ce sans avoir besoin l'interface de ligne de commande que ce soit ou pas du tout même. La manière que je peux accéder à ce est en utilisant le bouton de débogage au sommet de l'IDE de CS50. Maintenant, dans le passé, ce que nous avons vu est que nous utilisons la commande ligne pour compiler puis exécuter un programme. Le bouton de débogage fait ces deux étapes. Mais il apportera également le onglet débogueur sur l'extrême droite qui nous permet d'inspecter une variété des propriétés du programme car il est en cours d'exécution. Si je clique débogage, dans ce cas, il mettra en place un nouvel onglet dans la console fenêtre au bas. Et vous pouvez voir que cet onglet a quelques informations au sommet. Et nous pouvons largement ignorer. Mais l'une des choses que nous voulons remarquer est qu'il délivre la même chose que nous obtiendriez si nous avons essayé de faire fonctionner sur le programme de C dans la fenêtre de terminal. Ici, nous pouvons voir qu'il est en cours d'exécution clang, et il a une variété de drapeaux, et il compile notre fichier count.c, qui était l'onglet sélectionné au moment que je frappe débogage. Donc, ce qui est très utile car maintenant en utilisant ce bouton de débogage, nous pouvons simultanément compiler et puis exécuter le programme que nous avons fait vouloir courir. Un des drapeaux qui est importante, dans ce cas, nous avons été effectivement à l'aide le plus longtemps mais aussi juste fait une main agitant [inaudible], qui est-ce un ici. Dans clang, il dit -ggdb3. Dans ce cas, ce que nous sommes dire clang, notre compilateur, est que nous voulons compiler notre programme. Mais aussi de fournir ce sont appelé informations de symbole afin que le compilateur a effectivement accès à beaucoup de l'information sous-jacente contenue dans le programme. Plus précisément, le nombre des fonctions que je dois, les noms de ces fonctions, les variables, les types que ces variables sont, et une variété d'autres choses qui aident le débogueur effectuer son fonctionnement. Maintenant, il ya quelque chose d'autre ce qui est important de mentionner lorsque nous parlons en marche un programme de cette manière. Notez qu'il a fait donné un nouvel onglet dans notre console le long du fond. Nous avons plus d'interagir directement avec la fenêtre du terminal. Mais ce nouvel onglet est en fait une fenêtre de terminal. Il est juste spécifique à la gestion programme que nous avons créé. Notez que dans le bas, en combinaison avec une certaine sortie clang par le compilateur et GDB, que nous ne pouvons ignorer en grande partie, elle montre en fait la sortie de notre programme tout en bas. Maintenant, il est important de réaliser ce qui en fait une fenêtre va vous montrer la sortie de votre programme mais peut aussi accepter l'entrée pour ce programme, ainsi. Donc, avis qui dit s'il vous plaît entrer un numéro, qui est la même sortie que nous avions eu dans la fenêtre du terminal avant. Mais il est maintenant représenté dans ce nouvel onglet. Je peut entrer un numéro. Et il sera en fait fonction que nous attendons nous montrant notre débogage, la production, la sortie qui pourrait être buggé, que nous avons vu auparavant. Et tout en bas, il a fait quelque sortie supplémentaire du PIB juste que ce programme est terminé. Maintenant que vous avez vu dans ce notamment grâce à terme, il n'a pas été particulièrement utile parce que même si nous avions le menu du débogueur venir jusqu'à, ce fut encore un programme de course. A aucun moment, il fait suspendre l'exécution pour nous pour être en mesure d'inspecter tous les variables contenues dans. Il ya autre chose que nous avons à faire pour pour obtenir GDB de reconnaître que nous voulons à suspendre l'exécution du programme et ne pas laisser tout cela de procéder normalement comme nous le ferions dans tout autre cas. Pour suspendre l'exécution, à une certaine ligne spécifique, nous avons besoin pour créer ce qui est appelé un point de rupture. Et un point de rupture est très facilement créé dans ce CS50 IDE en prenant votre souris et en cliquant directement sur la gauche de certains numéro de ligne spécifique. Une fois que je fais ça, un point rouge apparaît, qui indique que cette ligne est maintenant un point de rupture. Et la prochaine fois que je dirige GDB, il va arrêter l'exécution à ce point de rupture quand il atteint cette ligne de code. Maintenant, ceci est une importante chose à réaliser qu'il est pas nécessairement le cas que chaque ligne de code est en fait accessible. Si je devais créer une fonction ici, pour F-- vide example-- et juste faire une ligne d'impression ici-- bonjour monde-- si je ne appeler cette fonction, ce sera le cas que, si je mets un point d'arrêt ici, la fonction ne sera jamais appelé. Et donc, ce notamment le point de rupture ne sera jamais fait une pause exécution du programme. Donc, disons que je crée correctement un point sur certaines ligne de code de pause qui seront effectivement exécutés. Or, dans ce cas, cela est le première ligne dans la fonction principale. Donc, ce sera certainement le cas que, dès que je commence l'exécution, la première ligne sera atteint. GDB va suspendre l'exécution. Et puis, je vais être en mesure de interagir avec le débogueur. Vous pouvez définir plusieurs lignes que points d'arrêt, si vous le souhaitez. Nous pouvons également créer un line up ici, dans ce segment de code qui ne sera jamais atteint. Et nous pouvons également mettre un peu plus loin. La raison pour laquelle nous le ferions vouloir faire cela nous allons aller dans un peu plus détail dans un instant. Donc pour l'instant, permettez-moi simplement désactiver ces points de rupture supplémentaires de sorte que nous pouvons regarder ce qui se passe quand je dois une seule pause point de mon programme. Je l'ai fait quelques changements à ce programme. Donc, je dois le sauver. Je vais cliquez sur débogage afin que je puisse commencer la compilation, puis exécution du débogueur. Nous allons voir que, après les moments, les la ligne que nous avons sélectionnés comme la pause point est surligné en jaune. Nous pouvons également remarquer que dans le en haut à droite dans le panneau de débogage que l'icône de pause a tourné dans une petite icône de lecture. Cela signifie que nous avons une pause l'exécution, dans ce cas particulier. Et frapper serait sur le bouton Lecture nous permettent de reprendre l'exécution à ce point précis. Notez qu'il ya une couple d'autres boutons disponibles dans ce panneau de débogage, aussi. Enjamber, ce qui me permet de exécuter cette seule ligne de code et enjamber à cette ligne à la suivant, qui, dans ce cas, signifierait que le printf instruction est exécutée. Et ce sera alors une pause l'exécution de la ligne 13, comme tant. Et il ya aussi une étape en fonction, qui est utile si je l'ai créé d'autres fonctions ailleurs dans le code source. Et je veux entrer dans ces fonctions plutôt que exécuter cette fonction dans son ensemble. Mais nous allons examiner plus à l'étape en fonction dans un instant. Maintenant, remarquez d'autres choses qui exister réellement dans ce panneau de débogage. Nous avons ce panneau appelé pile d'appel, qui nous montre où nous en sommes exactement. Dans ce cas, nous sommes à l'intérieur de la fonction principale. Notre script est appelé count.c. Et il nous arrive d'être sur ligne 13, première colonne, qui est précisément ce que la région en surbrillance du code source indique ainsi. Maintenant, remarquez que cela montre aussi en vertu de la section variable locale toutes les variables qui exister à l'intérieur de cette fonction. Il est important de noter que toutes les variables apparaîtront dans cette variable locale section dans une fonction, avant même qu'ils sont définis. Nous pouvons voir ici que nous avons une variable appelé num, a une valeur par défaut de 0, et il est de type int. Maintenant, avant de nous initialisons effectivement toutes ces variables, nous ne sommes pas nécessairement garantie de voir une valeur de 0. Et selon d'autres exécutions que vous avez effectué et l'état de votre mémoire lorsque vous avez réellement exécutez ce programme, vous pourriez découvrir que vous ne pas voir les valeurs de 0 et, à la place, d'autres chiffres fous. Mais ne vous inquiétez pas à ce sujet. Ça ne va pas être concerné jusqu'à initialiser fait la valeur. Or, dans ce cas, nous pouvons voir que Je l'ai effectué quelques sorties. Et je suis, en ce moment, une pause l'exécution. Mais dans ce cas, ce Je veux vraiment faire est à l'étape maintenant plus de cette ligne du code de sorte que je peux réellement interroger l'utilisateur pour ce qui int nous voulons utiliser dans notre programme. Or, dans ce cas, lorsque Je frappe enjamber, un avis que la Pause ou plutôt le CV bouton a changé à ce bouton Pause car ce code est effectivement en cours d'exécution. Que se passe-t-il est en ce moment qu'il est nous attendait à l'entrée de l'information comme nous pouvons voir notre texte de sortie tout au fond. Donc maintenant, cela est pas réellement pause, même si elle, en quelque sorte, semble être parce que rien ne se passe. Mais il se trouve que, dans mon cas précis de la ligne 13, Je suis en attente pour l'entrée utilisateur. Et ainsi de GDB est pas en mesure d'inspecter un programme car il est en cours d'exécution. Maintenant, la prochaine fois que je rentre un peu input-- donc je vais entrer dans ce numéro 5, comme nous l'avons vu dans le past-- frappé retour, et nous Notez que, immédiatement, pauses GDB et, encore une fois, met en évidence la ligne suivante. Mais remarquez que maintenant, en tant que résultat de notre saisi une valeur, nous avons mis à jour cette valeur à l'intérieur de nos variables locales, qui est très utile de savoir précisément ce que ce nombre était en mémoire. Maintenant, je peux permettre à ce programme pour continuer la lecture jusqu'à la fin de son exécution en frappant CV. Nous pouvons voir que très rapidement fait la finition du programme d'exécution avec la même sortie que l'on eu avant, le débogueur ferme, et maintenant ce programme a complètement cessé. Je montre que seulement pour le fins de voir ce que qui se passe quand nous avons frappé effectivement CV. Mais nous avons effectivement allons envie de retourner dans ce programme afin que nous puissions essayer de débogage précisément ce qui se passe. Maintenant que je suis en utilisant le débogueur, je peut pas besoin de ces déclarations débogage printf. Donc, je pouvais les enlever comme je vais le faire maintenant juste pour revenir à notre code simple que nous avions il ya un instant. Maintenant, quand je économise le programmer et exécuter, il sera, à nouveau, aller à cette initiale point de rupture que je devais à la ligne 11. Et je serai en mesure d'inspecter mes variables que je veux faire. Il se trouve que cette partie ne soit pas très intéressant, Et je sais que je vais imprimer cette déclaration. S'il vous plaît entrer un numéro. Et puis, je sais que je vais demander à l'utilisateur de cet entier. Alors peut-être, je veux vraiment bouger mon point de rupture un peu plus bas. Vous pouvez supprimer des points de rupture en cliquant, à nouveau, directement à la gauche de ce numéro de ligne. Ce point rouge disparaîtra, indiquant que ce point de rupture est maintenant disparu. Or, dans ce cas, l'exécution a été suspendue. Et si ça ne se passe réellement à reprendre dans ce cas particulier. Mais je peux mettre une pause signaler un peu plus tard. Et quand je reprends maintenant mes code, il va reprendre et de dire le point de ce point de rupture. Encore une fois, je frappe CV. Ne semble pas comme quelque chose qui se passe. Mais cela est parce que mon code est en attente d'entrée. Je vais entrer un numéro 5, appuyez sur Entrée, et Maintenant, la prochaine point de rupture sera atteint. Or, dans ce cas, ce est la ligne de code que, avant, nous savions qui est arrivé à être buggy. Donc, nous allons évaluer ce qui se passe à ce moment précis dans le temps. Quand une ligne est en surbrillance, ce ligne n'a pas encore été exécuté. Donc dans ce cas, nous pouvons voir que je ai un certain nombre, qui Je dois un entier appelé num qui a une valeur 5. Et je vais être performants un peu de maths sur ce numéro. Si je fais un pas sur cela, nous pouvons remarquer que la valeur de num a changé conformément à la arithmétique que nous avons réellement fait. Et maintenant que nous sommes à l'intérieur de cette boucle ou maintenant que la boucle lui-même est mis en évidence, nous voyons que nous avons un nouveau variable i appelé que qui va être utilisé en ce que pour la boucle. Maintenant, rappelez-vous avant que je dit que, parfois, vous êtes aller voir une sorte de fou numéros défaut avant que ce nombre ou que variable est en fait initialisées. Nous pouvons voir que précisément ici dans la cette variable appelé i, qui n'a pas encore été initialisé au moment de mettre en évidence. Mais nous pouvons voir qu'il a un certain nombre que nous ne serions pas fait attendre. C'est bon. Ne vous inquiétez pas à ce sujet parce que nous avons pas réellement initialisé ce nombre jusqu'à ce que je enjamber cette ligne et la valeur i a été initialisé à la valeur 1. Donc, pour voir que ce est effectivement le cas, nous allons passer par-dessus. Nous pouvons maintenant voir que ce ligne a été exécuté. Et nous sommes maintenant soulignons cette ligne de printf. Et nous pouvons maintenant voir comment nos valeurs de i et 3 ont changé au fil du temps. Ceci est très utile de faire, en fait, est à l'étape sur les lignes à plusieurs reprises. Et vous pouvez trouver ce que fait passe à l'intérieur de votre boucle for et ce qui se passe à la les variables à l'intérieur de cette boucle comme que l'exécution du programme se produit une étape à la fois. Maintenant, à ce stade, je enjambé juste assez que je suis maintenant à la fin de mon programme. Si je fais un pas sur cela, il sera fait cesser l'exécution comme nous l'avons vu dans le passé. Permettez-moi de redémarrer ce, encore une fois, de sorte que je peux pointer quelque chose d'autre, aussi. Dans ce cas, il est maintenant me demander, à nouveau, pour un certain nombre, qui Je vais, encore une fois, entrez. Mais cette fois, je vais entrer dans un nombre plus grand de sorte que la boucle for va parcourir plusieurs fois. Dans ce cas, je vais pour entrer une valeur de 11. Maintenant, encore une fois parce que je mets un point à la ligne 15 de la pause, il va mettre en évidence cette ligne. Nous pouvons voir que notre Numéro 11 est correctement représentés dans nos variables locales. Enjambant que nous pouvons maintenant regardez ce qui arrive à notre valeur de i que nous procédons à l'intérieur de cette boucle. Il obtient incrémenté à chaque fois nous avons de atteindre le sommet de cette boucle. Or l'une des choses qui pourraient être utile de le faire lors de l'exécution de ce programme est pour moi de fait modifier les variables midstream pour voir ce qui arrive à mon programme. Dans ce cas, je peux réellement double-cliquez sur la valeur. Notez que cela devient un champ de texte. Maintenant, je peux entrer différente valoriser tout pour voir comment mon programme se comporte quand je l'ai changé cette variable. Or, dans ce cas, la variable i contient maintenant la valeur 10. Mais le programme est encore pause dans l'exécution. Lorsque je fais un pas plus, je vois que le valeur i, qui je suis entré en tant que 10, est inférieure ou égale à la valeur de num, ce qui provoque immédiatement la boucle de cesser d'exécuter. Maintenant que est pas la seule raison pour laquelle vous le feriez vouloir modifier la variable en place. Vous pourriez veulent réellement pour essayer de le modifier de manière que vous pouvez continuer exécution d'une boucle ou de sorte que vous pouvez modifier une certaine valeur avant atteint un certain ensemble spécifique de l'arithmétique que vous vous apprêtez à effectuer. Alors, maintenant que nous avons réellement changer la valeur de i que le programme a été exécuté, il a causé la boucle de quitter prématurément en raison, tout d'un coup, i se trouvait être supérieure à la valeur NUM, ce qui signifie que pour que la boucle ne sont plus nécessaires à exécuter. En outre, il est arrivé à être le cas que nous avons changé la valeur de i lorsque la ligne 17 a été soulignée, qui était le point dans le temps pour que l'exécution de la boucle a été effectivement évalués. Si je l'avais changé la valeur de i sur une ligne différente, dis 19, nous aurions vu différente comportement parce que la ligne 19 serait ont exécuté avant que la boucle condition a été réévalué. Or, à ce point, je suis, encore une fois, à la fin de ce programme. Et je ne peux permettre que cela procéder à mon programme permet de quitter naturellement. Mais il ya un certain nombre de choses qui sont importants à emporter à partir de cette discussion particulière. Vous devez évaluer vos propres hypothèses sur la façon dont le code doit être comporte. Chaque fois que vous pensez que quelque morceau de code que vous savez qui se passe au travail, cela pourrait être un drapeau rouge pour aller recul et d'évaluer, et être sûr que votre accession comment ce code fonctionne est effectivement vrai à la façon dont il est exprimé dans votre code source. Mais encore plus le point est, lorsque nous utilisons le débogueur, vous pouvez mettre des points d'arrêt au différentes lignes de code, ce qui provoquera le débogueur suspendre l'exécution à chacune de ces lignes afin que vous puissiez évaluer la mémoire ou même changer en place. Et encore une fois, rappelez-vous que vous pouvez créer plusieurs points d'arrêt afin que vous peut également reprendre l'exécution, sautez sur de grandes portions de code, et il va automatiquement en pause au prochain point de rupture. Il ya en fait plus avancé caractéristiques du débogueur, ainsi. Mais nous devrons vous renvoyer à quelques vidéos suivantes afin de vraiment démêler comment d'utiliser ces fonctions particulières. Pour l'instant, je vous remercie beaucoup pour regarder. Et bonne chance débogage.