[? DAN ARMADARAS:?] Hi, Im [? Dan Armadaras?]. Vandaag gaan we kijken naar debuggen. Niet alleen gaan we praten over een aantal technieken, maar we gaan kijken naar een aantal van de functies bevatte binnen de CS50 IDE die het mogelijk maken je gemakkelijk debuggen van een programma. Een voorbeeld van iets dat mis kan gaan en het is eigenlijk iets dat we al eerder hebben gezien. In dit geval is dit een C programma dat een integer accepteert de gebruiker, volgt dat door twee, en geeft de uitgang aan de gebruiker. Nu van wat we hebben gezien eerder in lezingen, We weten dat dit daadwerkelijk zal leiden specifieke soorten divisie problemen wanneer we hebben oneven nummers. Concreet zullen we gewoon weggooien iets achter de komma. Nu, we weten dat dit toevallig het geval. En als we lopen, kunnen we bevestigen onze vermoedens, eerste, door het opstellen. Dan, door het uitvoeren en het invoeren van een oneven aantal. Dit is niets nieuws. Maar dit is eigenlijk een voorbeeld van een bug die kunnen bestaan ​​binnen een groter programma dat wordt moeilijker op te sporen. Ook al weten we wat het probleem is de ware crux zou proberen te identificeren specifiek waar de fout zich voordoet, identificeren wat dat probleem is, en vervolgens de vaststelling van het. Dus bieden dit als een voorbeeld wat zou iets zijn dat weten we al, maar kan worden begraven op andere elementen van de code. Dus het openen van dit andere bron codebestand als voorbeeld, deze divisie probleem is nu deel van een groter programma. Nog steeds is misschien een beetje beetje gekunsteld, en we zou gemakkelijk kunnen identificeren, met name aangezien we dit enkel bespreken. Maar we kunnen achterhalen dat dit probleem kan bestaan ​​op een grotere schaal. Als ik dit compileren en nu voer het uit, voer een oneven aantal, we kunnen zien dat we niet precies krijgen de uitvoer die wij hebben verwacht. In dit specifieke geval, zouden we kunnen zeggen dat we willen alle nummers te tellen van een tot een aantal specifieke nummer. En we kunnen dat we zien een verscheidenheid aan kwesties hier als we uitvoeren, gewoon, 0 en 1 wanneer wij een ingang van 5. Dus we weten al dat Er is hier een probleem. Maar we kunnen niet precies weten wanneer dit probleem werkelijk bestaat. Nu een van de manieren waarop we kunnen proberen om dit op te lossen is iets dat we hebben al geïntroduceerd. We kunnen gewoon gebruik maken van het op een grotere schaal. Op lijn 14, hebben we Dit printf functie, die ons in staat om af te drukken uit de staat van de verschillende stukjes informatie. En dit is iets dat je moet benutten binnen uw programma om te proberen om erachter te komen wat is gebeurt in verschillende regels code. Dus zelfs als dit niet het eindresultaat dat we eigenlijk willen produceren uit dit programma, we nog steeds kunnen sommige debug hebben verklaringen waar we kan proberen te achterhalen precies wat gebeurt binnenkant van onze code. Dus in dit geval, zal ik printf met de debug-tag. In dit geval is slechts een debug-reeks dat ik up-zetten, zodat het zeer duidelijk in de output van mijn code wat het is dat ik wil laten zien. En de output hier het aantal we hebben berekend. In dit geval zou ik willen precies weten wat er gebeurt en vóór na een specifieke berekening. Dus ik kan een printf gebruiken voordat en daarna regel code. In dit geval, ik kon zelfs maken het een beetje meer duidelijk door te zeggen debug vóór en debuggen na zo dat ik mezelf niet te verwarren met meerdere regels die identiek uitzien. Nu als we deze en run hercompileer het, voer een nummer als vijf weer, kunnen we zien dat we hebben nu uitgang voor en na en vind dat we niet hebben gedaan een duidelijke splitsing of duidelijk dat het aantal dat we eigenlijk willen doen. Nu in dit geval is niet echt een duidelijke output. Het is niet echt een duidelijke uitkomst die we willen uit van dit specifieke programma. Dit is wederom een beetje gekunsteld. Maar, misschien, een van de dingen die we konden doen als de specificatie zei dat we willen dit delen door 2 en voeg 1-- dus met andere woorden, We willen dan up-- afronden we zouden weten dat we konden doe dat bepaalde ding, in dit geval. Hier nu weten we dat we zullen zijn in staat om 1 toe te voegen aan onze gehalveerd nummer. Laten we dit opnieuw te compileren en bevestigen dat dit gedraagt ​​de manier waarop we dat willen. We kunnen nu voor dat hebben, hebben we het nummer 5. Na, hebben we de nummer 3, die volgens onze specificatie is wat we wilden doen. Maar als we kijken naar de uitgang hier, we kunnen zien dat we een ander zouden kunnen hebben bug helemaal, dat is dat we beginnen onze telling van 0. Nu weer, dit is iets die we hebben gezien in het verleden en we kunnen vrij gemakkelijk te repareren. Maar in dit geval, we had ook het voordeel van het gebruik van de printf statement direct in de lus weten precies waar de die fout voorkwam. Dus printf verklaringen zijn zeer nuttig bij het helpen u bepalen waar, juist in uw broncode, een specifieke fout optreedt. En het is ook belangrijk om te beseffen dat, als we het schrijven van code, we kunnen aannames de toestand van een programma. Of we zouden aannames over welk deel van het programma is eigenlijk juist of onjuist wanneer later als we bouwen dat programma en maakt het deel uit van een complex en groter programma dat we ons realiseren dat sommige aspecten van die eigenlijk buggy. Met behulp van printf kan echt helpen beperken en te identificeren de regio's van een programma dat niet mag worden precies gedraagt ​​de manier waarop we verwacht op basis van onze veronderstellingen. Maar er is ander gereedschap beschikbaar, evenals, die ons in staat om te proberen te achterhalen waar een fout optreedt en, specifiek, welke dingen gebeuren binnen het programma. Dus met behulp van printf is zeer handig wanneer we willen om specifieke gebieden van identificatie een programma dat enkele bug te hebben. Maar het wordt ook vervelend na een tijdje. In dit geval is dit een relatief eenvoudig programma met slechts een of twee variabelen. En wordt het heel gemakkelijk voor ons om afdruk van de waarde van die variabelen in het geheel van het programma. Maar we zouden een ander hebben programma dat vele variabelen. En het kan niet helemaal worden zo gemakkelijk te gebruiken printf om te proberen om te evalueren wat er gebeurt aan elk van die variabelen het programma uitvoert. Er is een programma dat bestaat genoemd debugger programma. In dit geval degene die we zullen gebruik is de GNU debugger, of GDB, dat ons toelaat om de interne inspecteren werking van een programma op een meer gedetailleerde manier. We kunnen daadwerkelijk uit te voeren GDB vanaf de opdrachtregel hier door simpelweg te typen GDB en de commando dat we willen debuggen. In dit geval tellen. Nu in dit geval kunnen we zien dat het brengt ons naar een prompt die GDB zegt. En we kunnen eigenlijk commando's uitvoeren om GDB daadwerkelijk starten uitvoering van de programma, stoppen op bepaalde punten, evalueren van de variabelen en inspecteren van de variabelen die bestaan ​​in de programmastatus op dat moment, enzovoort. Het geeft veel kracht voor ons. Maar het is gewoon zo gebeurt dat de CS50 IDE ook levert een GUI of user interface voor GDB dat stelt ons in staat om dit te doen zonder de command line interface dan ook of helemaal niet zelfs. De manier waarop ik kan toegang tot die is met behulp van de debug-toets op de top van de CS50 IDE. Nu in het verleden, wat we gezien is dat we gebruik maken van de opdracht lijn te compileren en vervolgens uitvoeren van een programma. De debug-knop doet beide van deze stappen. Maar het zal ook brengen de tabblad debugger uiterst rechts die ons in staat stelt om een ​​verscheidenheid te inspecteren van de eigenschappen van het programma zoals wordt uitgevoerd. Als ik klik debug, in dit geval is, zal het te brengen een nieuw tabblad in de console venster op de bodem. En je kunt zien dat dit tabblad heeft wat informatie aan de top. En we kunnen grotendeels negeren. Maar een van de dingen dat we willen zien dat deze luidspreker het zelfde ding dat we zou krijgen als we probeerden te lopen maken op het C-programma in het terminal-venster. Hier kunnen we zien het draait Clang, en heeft diverse vlaggen, en het is het samenstellen van onze count.c bestand, die het geselecteerde tabblad op dat moment was dat ik raakte debug. Dus dit is erg handig, omdat nu met behulp van deze debug-knop, kunnen we tegelijkertijd compileren en vervolgens het programma uit te voeren dat we eigenlijk wilt uitvoeren. Een van de vlaggen die belang, in dit geval, we hebben eigenlijk geweest met voor de langste tijd maar ook gewoon deed wat de hand zwaaien [onhoorbaar], die is dit hier. In Clang, zegt -ggdb3. In dit geval, wat we vertellen Clang, onze compiler, is dat we willen ons programma te compileren. Maar ook wat zijn genaamd symbool informatie zodat de compiler daadwerkelijk toegang veel van de onderliggende informatie vervat in het programma. Meer specifiek, het aantal van de functies die ik heb, de namen van deze functies, de variabelen, de types dat deze variabelen zijn, en diverse andere dingen die de debugger helpen voeren de werking ervan. Nu is er iets anders Dat is belangrijk om te vermelden als we bespreken running een programma op deze manier. Merk op dat het eigenlijk bracht een nieuw tabblad in onze console langs de bodem. We hoeven niet langer te interageren rechtstreeks met de terminal-venster. Maar deze nieuwe tabblad is eigenlijk een terminal venster. Het is gewoon eigen aan de lopende programma dat we hebben gecreëerd. Merk op dat bij de bodem, in combinatie met enkele uitgang kletteren door de compiler en de GDB, die kunnen we grotendeels negeren, het eigenlijk toont de uitvoer van ons programma op de bodem. Nu is het belangrijk om te beseffen dat dit venster eigenlijk zal u de uitvoer van je programma maar ook kan invoeren accepteren voor dat programma, ook. Zo bericht dat zegt Voer een getal, die dezelfde uitvoer die we hadden had in de terminal venster voordat. Maar het is nu getoond in deze nieuwe tabblad. Ik kan een nummer invoeren. En het zal in feite functie als we verwachten toont ons onze debug, output, de uitvoer die misschien buggy, zoals we eerder hebben gezien. En helemaal onderaan het heeft eigenlijk een aantal extra uitgang van het BBP gewoon te zeggen dat dit programma is voltooid. Nu zoals je zag in deze bijzonder lopen door, het was niet bijzonder handig omdat zelfs al hadden we de debugger menu komen up, was dit nog steeds een lopend programma. Op geen enkel moment heeft het eigenlijk pauzeren uitvoering voor ons kunnen al inspecteren de variabelen in ons systeem. Er is iets anders dat we moeten doen om om GDB krijgen om te erkennen dat we willen om de uitvoering van het programma te pauzeren en niet alleen toestaan ​​doorgaan normaal gesproken als we zouden in elk ander geval. Om uitvoering te pauzeren, bij een aantal specifieke lijn, we nodig hebben om te creëren wat riep een breekpunt. En een breekpunt is heel gemakkelijk gemaakt in deze CS50 IDE door het nemen van uw muis en naar links te klikken direct van enkele specifieke lijnnummer. Zodra ik dat doe, een rode stip verschijnt, wat aangeeft dat die lijn is nu een breekpunt. En de volgende keer dat ik run GDB, dat stopt de uitvoering op dat breekpunt wanneer dat regel code bereikt. Nu is dit een belangrijke ding om te realiseren dat het niet noodzakelijk de zo dat elke regel code in feite bereikbaar. Als ik naar een functie te creëren hier, voor example-- leegte F-- en gewoon doen een afdruk lijn hier-- hello wereld-- als ik nooit deze functie aan te roepen, Het is het geval dat, als ik een break point hier, de functie niet genoemd. En daarom, dit bijzonder breekpunt zal nooit echt pauzeren uitvoering van het programma. Dus laten we zeggen dat ik het goed maak een breekpunt op enkele regel code dat daadwerkelijk wordt uitgevoerd. Nu in dit geval is dat het eerste lijn in de belangrijkste functie. Zo zal het zeker het geval dat, zodra ik beginnen met de uitvoering, de eerste lijn zal worden bereikt. GDB zal uitvoering pauzeren. En dan zal ik in staat te zijn interactie met de debugger. U kunt meerdere regels als set breekpunten, als je zou willen. We kunnen ook een lijn te creëren up hier in dit segment van de code dat zal nooit worden bereikt. En we kunnen ook een verder hieronder. De reden dat we zouden wil dit We doen gaan in een beetje meer detail in slechts een moment. Dus voor nu, laat me gewoon uitschakelen deze extra breekpunten zodat we kunnen kijken naar wat er gebeurt als ik één break punt in mijn programma. Ik heb gedaan wat veranderingen in dit programma. Dus ik nodig om het te redden. Ik zal klikken debug, zodat ik kan beginnen met het samenstellen en vervolgens uitvoering van de debugger. We zullen zien dat, na momenten, de lijn die wij als de pauze gekozen punt is geel gemarkeerd. We kunnen ook merken dat er in de rechtsboven in het debug panel dat het pauzepictogram heeft gedraaid in een klein spel icoon. Dit betekent dat we pauze uitvoeren, in dit geval. En het raken van de Play-knop zou ons toelaten om de uitvoering te hervatten op dat specifieke moment. Merk op dat er een paar andere knoppen beschikbaar in debug paneel, ook. Stap over, die mij toelaat om voeren dat een regel code en stap over naar die lijn naar de volgende, die in dit geval, zou betekenen dat de printf instructie wordt uitgevoerd. En het zal dan pauzeren executie op lijn 13, zoals zo. En er is ook een stap in functie, waarin is handig als ik andere hebben gecreëerd functies elders in de broncode. En ik wil om de stap naar die functies plaats voeren die functie als geheel. Maar we zullen meer kijken naar de stap in functie in slechts een moment. Nu een aantal andere dingen die werkelijk bestaan ​​binnen deze debug panel. Wij hebben dit panel genaamd de noemen stack, die ons laat zien waar we precies zijn. In dit geval zijn wij binnen van de hoofdfunctie. Ons script wordt genoemd count.c. En we toevallig op te zijn lijn 13, kolom één, die is precies wat de gemarkeerde regio van de broncode aangeeft, ook. Nu merken dat dit toont ook onder de lokale variabele sectie alle variabelen die bestaan ​​binnen deze functie. Het is belangrijk op te merken dat alle variabelen verschijnt in deze lokale variabele sectie binnen een functie, zelfs voordat ze zijn gedefinieerd. We kunnen hier zien dat we een variabele num genaamd, heeft een standaard waarde van 0, en het is van het type int. Nu voordat we daadwerkelijk initialiseren al deze variabelen, we zijn niet noodzakelijkerwijs gegarandeerd een waarde van 0 te zien. En afhankelijk van andere uitvoeringen die je hebt uitgevoerd en de staat van je geheugen als je eigenlijk dit programma uitvoert, je zou kunnen vinden dat je niet de waarden van 0 niet zien en in plaats daarvan een andere gekke nummers. Maar maak je geen zorgen over. Het gaat niet relevant tot zijn je eigenlijk initialiseren van de waarde. Nu in dit geval, kunnen we dat zien Ik heb uitgevoerd een aantal uitgangen. En ik ben, nu, zweeg uitvoering. Maar in dit geval, wat Ik echt wil doen is nu stap over deze lijn van de code, zodat ik kan eigenlijk zoekopdracht van de gebruiker voor die int die we willen gebruiken in ons programma. Nu in dit geval, wanneer Ik raakte stap over, bericht dat de Pauze of liever de Resume knop is veranderd om dit pauzeknop omdat deze code daadwerkelijk uitvoert. Wat gebeurt er nu is dat het op ons te wachten voor het invoeren van een aantal gegevens zoals we kunnen zien door onze output tekst helemaal onderaan. Dus nu, dit is eigenlijk niet onderbroken, hoewel het, soort van, verschijnt te zijn, omdat er niets gebeurt. Maar het is gewoon zo gebeurt het dat in mijn specifieke geval op lijn 13, Ik wacht op input van de gebruiker. En dus GDB is niet in staat om te inspecteren een programma dat wordt uitgevoerd. Nu is de volgende keer dat ik dient een input-- dus zal ik dat nummer 5 in te voeren, zoals we hebben gezien in de past-- hit Return, en we opmerken dat, onmiddellijk, GDB pauzes en, opnieuw, wijst op de volgende regel. Maar merken dat nu, als een resultaat van onze het invoeren van een waarde, we hebben die waarde binnen bijgewerkt van onze lokale variabelen, die is zeer nuttig om precies te weten Wat dat nummer is in het geheugen. Nu kan ik toestaan ​​dat dit programma voort te zetten spelen totdat het einde van de uitvoering door het raken van CV. We kunnen zien dat heel snel doet het programma afwerking uitvoeren met dezelfde uitgang die we had vóór, de debugger sluit, en nu dit programma is volledig gestopt. I blijkt dat slechts de toepassing van zien wat gebeurt er als we daadwerkelijk getroffen hervatten. Maar we eigenlijk gaan willen terug te gaan in dit programma zodat we kunnen proberen te debuggen precies wat er gebeurt. Nu dat ik het gebruik van de debugger, kan ik niet deze debug printf verklaringen nodig. Dus ik kon ze te verwijderen als ik zal doen nu alleen maar om terug te gaan naar onze eenvoudiger code dat we een ogenblik geleden. Nu wanneer ik sla de programmeren en uit te voeren, zal, opnieuw naar die initiële break punt dat ik had op lijn 11. En ik zal in staat zijn om te inspecteren mijn variabelen zoals ik wil doen. Het is gewoon zo gebeurt het dat deze deel is niet erg interessant, En ik weet dat ik ga uit te printen deze verklaring. Vul een getal. En dan, ik weet dat ik ga de gebruiker die integer stellen. Dus misschien, ik eigenlijk wilt verplaatsen mijn break punt een beetje verder naar beneden. U kunt breekpunten verwijderen door te klikken op, opnieuw, direct links van die lijnnummer. Dat red dot zal verdwijnen, wat aangeeft dat breekpunt nu is verdwenen. Nu in dit geval uitvoering is onderbroken. En zo gaat het eigenlijk niet van plan om hervatten in dat geval. Maar ik kan een pauze instellen wijzen een beetje later. En als ik nu weer mijn code, het zal hervatten en vertel het punt van dat breekpunt. Nogmaals, ik raakte hervatten. Lijkt niet als iets gebeurt. Maar dat komt omdat mijn code wacht op invoer. Ik zal een aantal 5 in te voeren, druk op Enter, en nu de volgende breekpunt zal worden getroffen. Nu in dit geval is dit is de regel code dat, voordat we wisten is er gebeurd met buggy zijn. Dus laten we evalueren wat er gebeurt op dit moment. Als een regel is gemarkeerd, dit lijn nog niet is uitgevoerd. Dus in dit geval, kunnen we zien dat ik een nummer, dat Ik heb een integer genoemd num dat een waarde 5 heeft. En ik ga optreden wat wiskunde op dat nummer. Als ik stap over, dat we kunnen merken dat de waarde van num veranderd overeenkomstig de rekenkunde dat we eigenlijk hebben gedaan. En nu dat we binnenkant van deze lus of nu de lus zelf is gemarkeerd, we zien dat we een nieuwe variabele genaamd i die zal worden gebruikt in die lus. Nu herinner voordat ik gezegd dat je soms bent gaat om een ​​soort van gekke zien nummers als standaard voor dat getal of die variabele eigenlijk geïnitialiseerd. We kunnen precies zien dat Hier in deze variabele riep ik, die niet heeft Nog geïnitialiseerd op het moment van het benadrukken. Maar we kunnen zien dat het een getal dat we eigenlijk niet verwacht. Dat is geen probleem. Maak je geen zorgen over want we hebben niet echt geïnitialiseerd dat nummer totdat ik stap over deze lijn en de waarde i is geïnitialiseerd op de waarde 1. Dus om te zien dat dat eigenlijk het geval is, laten we stap over. We kunnen nu zien dat lijn is uitgevoerd. En we zijn nu markeren Dit printf lijn. En we kunnen nu zien hoe onze waarden van i en 3 zijn veranderd in de tijd. Dit is nuttig om te doen, in feite, is herhaaldelijk stap over lijnen. En je kunt wat eigenlijk vinden gebeurt binnenkant van de lus en wat gebeurt er met de variabelen binnenkant van die lus als programmauitvoering optreedt één stap tegelijk. Nu op dit punt, ik stapte over net genoeg dat ik nu ben aan het eind van mijn programma. Als ik stap over dat, het zal eigenlijk ophouden uitvoering zoals we hebben gezien in het verleden. Laat me opnieuw dit, wederom, dus dat ik iets anders kan wijzen, ook. In dit geval is me nu vraagt, wederom, een nummer dat Ik zal, nogmaals, in te voeren. Maar deze keer, ik ga in te voeren een groter aantal, zodat de lus zal herhalen keer. In dit geval, ga ik een waarde van 11 invoeren. Nu weer omdat ik ingesteld een breekpunt op lijn 15, het gaat om die lijn te markeren. We kunnen zien dat onze nummer 11 correct vertegenwoordigd in onze lokale variabelen. Intensivering over dat, we kunnen nu kijk wat er gebeurt in onze waarde van i als we verder binnenkant van deze lus. Het wordt opgehoogd elke keer als we bereikt de top van dat voor de lus. Nu is een van de dingen die zouden kunnen nuttig zijn tijdens uitvoering van dit programma is voor mij eigenlijk veranderen de variabelen midstream te zien wat gebeurt er met mijn programma. In dit geval, kan ik eigenlijk Dubbelklik op de waarde. Merk op dat het een tekstveld. Nu kan ik anders in te voeren waardeert totaal om te zien hoe mijn programma gedraagt als ik die variabele ben veranderd. Nu in dit geval de variabele i bevat nu de waarde 10. Maar het programma is nog steeds gepauzeerd in de uitvoering. Toen ik stap over, zie ik dat de waarde i, die ik ingevoerd als 10, niet groter is dan de waarde van num, waardoor meteen de lus stoppen uitvoeren. Nu is dat niet de enige reden waarom je zou willen de variabele in de plaats te wijzigen. Je zou eigenlijk willen om te proberen om het zo te wijzigen dat u kunt blijven uitvoeren van een lus of zo, dat u kunt wijzigen zekere waarde vóór een aantal specifieke set van rekenkundige bereikt dat je op het punt om uit te voeren. Dus nu dat we eigenlijk veranderen waarde van i het programma werd uitgevoerd, het veroorzaakt de lus te stoppen voortijdig want ineens, i toevallig groter is dan de waarde van num, wat betekent dat voor de lus niet meer nodig te worden uitgevoerd. Verder is er gebeurd met de te Indien we veranderde de waarde van i als de lijn 17 werd benadrukt, welke het tijdstip was dat de voor de uitvoering lus eigenlijk geëvalueerd. Als ik de waarde van was veranderd ik op een andere lijn, zeggen 19, zouden we anders hebben gezien gedrag omdat de lijn 19 zou hebben uitgevoerd voordat de lus voorwaarde werd opnieuw geëvalueerd. Nu op dit punt, ik ben, nogmaals, Aan het einde van het programma. En ik kan toestaan ​​dat deze over te gaan tot toestaan ​​dat mijn programma op natuurlijke wijze af te sluiten. Maar er zijn een paar dingen die belangrijk zijn om mee te nemen zijn van deze bijzondere discussie. Je nodig hebt om te evalueren je eigen aannames over hoe de code moet worden gedragen. Elke keer als je denkt dat een stukje code weet je toevallig aan het werk, dat een rode vlag te gaan zou kunnen zijn rug en te evalueren, en zorg ervoor dat dat uw aanname van hoe die code werkt is eigenlijk waar de manier waarop het is uitgedrukt in uw broncode. Maar nog meer punt was, wanneer we met behulp van de debugger, U kunt breekpunten op te zetten verschillende regels code, die de debugger te veroorzaken pauzeren uitvoering op elk van die lijnen zodat u kunt evalueren geheugen of zelfs veranderen in de plaats. En nogmaals, vergeet niet dat je kunt creëren van meerdere breekpunten, zodat u kan ook worden hervat uitvoering, skip over grote delen van de code, en het zal automatisch pauzeren bij de volgende breekpunt. Er is eigenlijk meer geavanceerde kenmerken van de debugger, ook. Maar we moeten u verwijzen wat latere video om echt te plagen elkaar hoe die specifieke functies. Voor nu, dank u heel erg voor het kijken. En veel geluk debuggen.