[? DAN ARMADARAS :?] Hi, Eu son [? Dan Armadaras?]. Hoxe, nós estamos indo a estar a ollar para a depuración. Non só estamos indo a falar sobre algunhas técnicas, pero tamén imos ollar para algunhas das características contidas dentro do IDE CS50 que permiten vostede depurar facilmente un programa. Só un exemplo de algo que pode dar mal e é realmente algo que xa vimos antes. Neste caso, trátase dun programa C que acepta un enteiro dende o usuario, divide por dous, e ofrece a saída ao seu usuario. Agora, a partir do que vimos anteriormente en conferencias, sabemos que isto vai realmente causar tipos específicos de problemas de división cando temos números impares. En concreto, imos simplemente tirar algo despois do punto decimal. Agora sabemos que este pasa a ser o caso. E se nós executalo, podemos confirmar nosas sospeitas, primeiro, compilando. E, a continuación, executando e inserindo un número impar. Iso non é novidade. Pero este é realmente un exemplo dun erro que pode existir dentro dun programa máis que se fai máis difícil de rastrexar. A pesar de sabermos cal é o problema é, o certo cerne da cuestión pode estar tentando identificar especialmente onde a erro ocorre, identificar o que este problema é, a continuación, fixándose o. Por iso, proporcionar isto como un exemplo do que podería ser algo que xa sabemos, pero pode ser enterrado dentro doutros elementos do código. Así, abrindo esta outra fonte arquivo de código como un exemplo, este problema de división é agora parte dun programa máis grande. Aínda pode ser un pouco pouco artificial, e nós Pode ser capaz de facilmente identificalo, especialmente xa que estamos só discutindo iso. Pero podemos descubrir que esta problema pode existir nunha escala maior. Se eu compilar iso e agora executalo, escriba un número impar, vemos que non conseguimos precisamente a saída que podemos esperar. Neste caso particular, poderiamos dicir que nós quere contar todos os números de un a un número específico. E vemos que ten unha variedade de cuestións aquí se está saída simplemente 0 e 1, cando nós fornecen unha entrada de 5. Entón, nós xa sabemos que hai un problema aquí. Pero nós non podemos saber con precisión onde este problema realmente existe. Agora, unha das formas que podemos tentar corrixir isto é algo que temos xa aparecen para. Podemos só usalo nunha escala maior. Na liña 14, temos esta función printf, o que nos permite imprimir o estado de varias pezas de información. E iso é algo que debe aproveitar dentro do seu programa para tratar de descubrir o que é pasando en varias liñas de código. Así, aínda que este non é o resultado final que, en realidade, quere producir fóra do Neste programa, aínda pode ter algunha depuración declaracións onde nós pode tentar descubrir exactamente o que está a suceder dentro do noso código. Polo tanto, neste caso, eu vou printf co tag de depuración. Neste caso, trátase só unha secuencia de depuración que eu estou poñendo-se a que se faga moi claro na saída do meu código que é o que quero amosar. E aquí o número de saída que temos calculado. Neste caso, eu podería quero saber exactamente o que está a suceder antes e tras algúns cálculos específicos. Entón eu podería usar un printf antes e despois de que a liña de código. Neste caso, eu podería incluso facelo un pouco máis clara dicindo depuración antes e depuración despois de tanto que eu non confundir-me con varias liñas que parecen idénticas. Agora, se nós recompilar este e executar Lo, escriba un número como cinco de novo, vemos que temos Agora saída antes e despois e cre que non fixemos unha clara división ou ter claro do número que realmente queremos facer. Agora, neste caso, esta é non é realmente unha saída clara. Non é realmente un resultado claro que queremos fóra deste programa particular. E isto é, de novo, unha pouco artificial. Pero, quizais, unha das cousas que poderíamos facer a especificación dixo que queremos dividir isto por 2 e engadir 1-- Así, noutras palabras, queremos redondear up-- continuación podemos saber que puidésemos facer esa cousa particular, neste caso. Agora aquí sabemos que seremos capaz de engadir 1 ao noso número á metade. Imos recompilar este e confirmar que esta está comportándose de maneira que queremos. Podemos ver que agora antes tendo, temos o número 5. Despois de que ten o número 3, que de acordo coa nosa especificación, é o que queriamos facer. Pero se miramos para o saída aquí, podemos ver que poderiamos ter outro Recheo completo, que é que estamos comezando a conta desde 0. Agora, de novo, iso é algo que vimos no pasado e que poidamos resolve moi facilmente. Pero, neste caso, nós tamén tiña o beneficio usar a instrución printf directamente dentro do loop for para saber exactamente onde que o erro estaba ocorrendo. Entón, son declaracións printf moi útil para axudar a determinar onde, precisamente no seu código fonte, un erro específico se produciron. E tamén é importante entender que, como estamos escribindo código, poderiamos ter premisas sobre o estado dun programa. Ou que teñamos premisas sobre o que parte do programa é realmente correcto ou incorrecto cando máis tarde, a medida que construímos sobre este programa e facelo parte dunha complexo e programa maior que nos damos conta de que algún aspecto de que é realmente buggy. Usando printf realmente pode axudar diminuír e identificar As rexións dun programa que non pode estar comportándose exactamente do xeito que nós esperar, en base ás nosas suposicións. Pero hai outras ferramentas dispoñible, así como, que nos permiten tratar figura fóra onde se produciron un erro e tamén, en concreto, o que as cousas están a suceder dentro do programa. Entón, usando printf é moi cando queremos útil para identificar áreas específicas de un programa que ten algún erro. Pero tamén se fai tedioso despois dun tempo. Neste caso, trátase dun programa relativamente sinxelo con só unha ou dúas variables. E tórnase moi fácil para nós imprimir o valor destas variables no contexto do programa máis grande. Pero podemos ter un diferente programa que ten moitas variables. E iso non pode ser completamente tan fácil de usar printf para tratar de avaliar o que está a suceder para cada unha destas variables como o programa está en execución. Hai un programa que existe chamado un programa depurador. Neste caso, a que iremos uso é o depurador GNU, ou GDB, que nos permite inspeccionar o interior funcionamento dun programa nun moito máis forma detallada. Podemos realmente executar GDB da liña de comandos aquí simplemente escribindo GDB e orde que desexe depurar. Neste caso, contan. Agora, neste caso, podemos ver que nos leva a un poder que se GDB. E podemos, de feito, executar comandos para GDB para efectivamente iniciar a execución do programa, paralo en certos puntos, avaliar as variables e inspeccionar as variables que existe no estado de programa naquel momento en particular, e así por diante e así por diante. Ofrece unha gran cantidade de enerxía para nós. Pero iso só acontece que o IDE tamén CS50 ofrece unha interface gráfica ou un usuario interface para que o GDB permítenos facelo sen necesidade de a interface de liña de comandos que sexa ou en todo mesmo. O xeito que eu poida acceder a este é usando o botón de depuración na parte superior do IDE CS50. Agora, no pasado, o que temos visto é que usamos o comando liña para compilar e, a continuación, realizar un programa. O botón de depuración fai ambos os pasos. Pero tamén vai traer o guía depurador na extrema dereita que nos permite inspeccionar unha variedade de propiedades do programa como está en execución. Se eu premer depuración, neste caso, será unha nova guía na consola ventá na parte inferior. E podes ver que esta guía ten unha información na parte superior. E podemos, en gran parte ignorar isto. Pero unha das cousas que queremos destacar é que exhiba o mesmo que nós obtería se intentamos executar make en o programa C na fiestra da terminal. Aquí podemos ver que funciona clang, e que ten unha variedade de bandeiras, e está compilando noso arquivo count.c, que foi o guía seleccionada no momento que eu bati de depuración. Entón iso é moi útil porque agora usando este botón de depuración, podemos simultaneamente compilar e, a continuación, realizar o programa que realmente quere facer. Unha das bandeiras que é importante, neste caso, fomos realmente usando por máis tempo pero tamén só fixen algunha man acenando [inaudível], que é este aquí. En clang, di -ggdb3. Neste caso, o que somos dicindo clang, o noso compilador, é que queremos para compilar noso programa. Pero tamén proporcionar o que son chamado de información símbolo para que o compilador realmente ten acceso para unha gran parte da información subxacente contido dentro do programa. En concreto, o número das funcións que eu teño, os nomes destas funcións, as variables, tipo que as variables son, e unha variedade de outras cousas que axudan o depurador realizar o seu funcionamento. Agora hai unha cousa que é importante mencionar cando estamos discutindo running un programa deste xeito. Teña en conta que ten, de feito, trouxo á tona unha nova guía no noso consola ao longo do fondo. Xa non teñen que interactuar directamente coa ventá do terminal. Pero este novo guía é de feito, unha fiestra de terminal. E só é específico para o funcionamento programa que creamos. Nótese que no fondo, en combinación con algunha saída por clang o compilador e GDB, que podemos ignorar en gran parte, que realmente mostra a saída de noso programa na parte inferior. Agora é importante entender que este diálogo realmente ha amosar-lle o saída do seu programa pero tamén pode aceptar a entrada para ese programa, así. Entón nota que di Introduza un número, que é o mesmo saída que tiña na fiestra da terminal antes. Pero agora aparece nesta nova guía. I pode introducir un número. E vai realmente función como esperamos mostrando noso depuración, de saída, a saída que se pode buggy, como vimos antes. E ben no fondo, el realmente ten algunha saída adicional do PIB só dicindo que este programa se completa. Agora, como viu neste especial de execución por medio, non foi particularmente útil porque aínda aínda tivemos o menú depurador vir se, este aínda era un programa en execución. En ningún momento realmente deter a execución para nós para poder inspeccionar todos as variables contidos. Hai algo máis que temos que facer, a fin para GDB recoñecer que queremos para deter a execución do programa e non só permitir que continúe normalmente como sería en calquera outro caso. Co fin de deter a execución, nalgunha liña específica, necesitamos crear o que é chamado un punto de ruptura. E un punto de quebra é moi facilmente creado neste CS50 IDE, tendo o seu rato e premendo directamente á esquerda dun número de liña específico. Xa que eu fago isto, un punto vermello aparece, o que indica que esta liña é agora un punto de ruptura. E a próxima vez que eu corro GDB, esta ha parar a execución nese punto de quebra cando alcanza esta liña de código. Agora, este é un importante cousa que entender que non é necesariamente o caso en que cada liña de código en realidade, é accesible. Se eu fose para crear unha función ata aquí, para F-- baleiro example-- e só facer unha liña de impresión aqui-- Ola mundo-- se eu nunca chamar esta función, que será o caso de que, se eu definir un break point aquí, a función nunca será chamado. E, polo tanto, este especial break point nunca realmente pausa a execución do programa. Entón, digamos que eu crear correctamente un punto de ruptura nalgún liña de código que vai realmente ser executado. Agora, neste caso, esta é a primeira liña na función principal. Por iso, será certamente o caso que, así que eu comezar a execución, a primeira liña será alcanzar. GDB vai parar a execución. E entón, eu serei capaz de interactuar co depurador. Podes establecer varias liñas como puntos de interrupción, se desexa. Tamén podemos crear unha liña superior aquí neste segmento de código que nunca será alcanzar. E nós tamén pode definir unha máis abaixo. A razón que nós quero facelo nós imos entrar nun pouco máis detalles en só un momento. Entón, por agora, déixeme só desactivar estes puntos de quebra adicionais para que poidamos ver que pasa cando eu teño unha única pausa punto no meu programa. Eu fixen algúns cambios a este programa. Entón, eu teño salvalo. Vou prema depuración para que eu poida comezar a compilación e, a continuación, execución do depurador. Veremos que, despois de momentos, os liña que foi seleccionada como a quebra punto é destacado en amarelo. Tamén podemos destacar que no parte superior dereita do panel de depuración que a icona de pausa converteuse nun pequeno icono de xogo. Isto significa que temos de pausa execución, neste caso en particular. E usar o botón Reproducir se permitir-nos seguir a execución nese punto específico. Teña en conta que hai un par de outro botóns dispoñibles neste panel de depuración, ben. Pasar por riba, o que me permite executar que unha liña de código e pasar por riba desa liña para o seguinte, o que, neste caso, significaría que o printf instrución é executada. E, a continuación, facer unha pausa execución na liña 13, así. E hai tamén un paso en función, que é útil se eu creei outro funcións noutras partes do código fonte. E quero entrar estas funcións, no canto de realizar esta función no seu conxunto. Pero imos ollar máis para o paso en función só en un momento. Agora notar algunhas outras cousas que realmente existen dentro do taboleiro de depuración. Temos este panel de chamada chamar pila, que nos mostra exactamente onde estamos. Neste caso, estamos dentro da función principal. Noso script chámase count.c. E nós ocorrer de ser en liña 13, columna un, que é precisamente o que a rexión en destaque do código fonte indica, como ben. Agora conta que isto tamén mostra baixo a sección variable local todas as variables que existen dentro esta función. É importante ter en conta que todas as variables aparecerá nesta variable local sección dentro dunha función, mesmo antes de ser definidas. Podemos ver aquí que temos unha variable chamado nun, ten un valor por defecto de 0, e é de tipo int. Agora, antes de que realmente arrincar todas estas variables, non somos necesariamente garantir a ver un valor de 0. E dependendo doutras execucións que executou eo estado da súa memoria cando realmente executar este programa, pode considerar que Non vexo valores de 0 e, no seu lugar, algúns outros números tolos. Pero non se preocupe con iso. Non vai ser relevante ata realmente arrincar o valor. Agora, neste caso, podemos ver que Teño realizado algúns saídas. E eu estou agora, parou a execución. Pero neste caso, o que Realmente quero facer é para o paso agora sobre esta liña de código para que eu poida realmente consultar o usuario para que int que queremos usar no noso programa. Agora, neste caso, cando Eu bati pasar por riba, aviso que a pausa ou mellor, o Resume botón cambiou a este botón de pausa porque este código é realmente execución. Que está a pasar Actualmente é que é esperando por nós para entrada de unha información como vemos polo noso texto de saída na parte inferior. Entón, agora, este é Non, en realidade, fixo unha pausa, aínda que, de certa forma, parece ser, porque nada está a suceder. Pero iso só acontece que, meu caso específico na liña 13, Estou agardando entrada do usuario. E así GDB non é capaz de inspeccionar un programa como está en execución. Agora, a próxima vez que eu entrar nalgúns input-- entón eu vou entrar nese número 5, como vimos no past-- bater Return, e nós Lembre que de inmediato, pausas GDB e, de novo, destaca a liña seguinte. Pero teña en conta que agora, como un resultado da nosa introducir un valor, nós actualizamos ese valor dentro das nosas variables locais, que Isto é moi útil saber con precisión o que este número estaba na memoria. Agora podo permitir que este programa continúe xogar ata o final da súa execución por bater Resume. Podemos ver que moi rapidamente fai o remate programa de execución coa mesma saída que tiña antes, o depurador pecha, e agora este programa deixou completamente. I mostran que só pola efectos de ver que acontece cando nós realmente bater Resume. Pero nós realmente están indo quero volver a este programa para que poidamos probar depurar precisamente o que está pasando. Agora que está a usar o depurador, podo Non precisa destas declaracións de depuración printf. Así eu podería eliminar-los como eu vou facer Agora, só para volver para o noso código máis sinxelo que tivemos un momento atrás. Agora, cando eu gardar o programar e executalo, ha, unha vez máis, ir aquel inicial punto que eu tiña na liña 11 romper. E eu vou ser capaz de inspeccionar meus variables como quero facer. Acontece que este parte non é moi interesante, E sei que vou imprimir esta declaración. Introduza un número. E entón, eu sei que eu vou pedir ao usuario para ese enteiro. Entón, talvez, realmente quero cambiar a miña punto de romper un pouco máis abaixo. Pode eliminar puntos de interrupción premendo de novo directamente á esquerda de que o número de liña. Ese punto vermello desaparecerá, indicando que ese punto de quebra é ir agora. Agora, neste caso, execución foi pausada. E por iso non é realmente indo retomar nese caso particular. Pero podo definir unha pausa apuntar un pouco máis tarde. E cando eu agora retomar a miña código, será retomada e dizer- a punto de que o punto de quebra. Unha vez máis, eu bati Resume. Non parece que nada está a suceder. Pero iso é porque a miña código está agardando entrada. Vou introducir un número 5, prema Intro, e Agora, o seguinte punto de interrupción será acadar. Agora, neste caso, este é a liña de código que, antes, sabiamos pasou a ser buggy. Entón, imos avaliar o que pasa neste momento particular no tempo. Cando unha liña é resaltada, este A liña non foi executado. Polo tanto, neste caso, podemos ver que eu teño un número, que Eu teño un número enteiro chamado Nun que ten un valor 5. E eu vou estar realizando un pouco de matemáticas en que número. Se eu pasar por riba diso, podemos entender que o valor para o núm cambiou de acordo co aritmética que temos realmente feito. E agora que estamos dentro deste loop ou agora que o loop for en si está en destaque, vemos que temos un novo variable chamada i que será utilizado na medida en que a lazo. Agora lembre se antes de que eu mencionou que ás veces está vai ver algún tipo de tolo números por defecto antes de ese número ou que é variable de feito iniciado. Podemos ver que precisamente aquí nesta variable chamado I, que non posúe Aínda non foi inicializado no momento de destacar. Pero podemos ver que ten un número que non sería realmente esperar. Está ben. Non hai problema con iso porque non temos, en realidade, iniciar ese número ata que eu pasar por riba desta liña eo valor i foi inicializar co valor 1. Entón, a ver que iso é, en realidade, o caso, imos pasar por riba. Podemos ver agora que ese A liña foi executada. E agora estamos destacando esta liña printf. E agora vemos como os nosos valores i 3 e cambiaron ao longo do tempo. Isto é moi útil para facer, de feito, é para pasar por riba de liñas repetidamente. E pode atopar o que realmente acontece dentro do seu loop for eo que acontece coa variables dentro dese loop como que a execución do programa ocorre un paso á vez. Agora, neste momento, eu pasou por riba só o suficiente que agora estou a finais do meu programa. Se eu pasar por riba diso, que vai realmente cesar execución como vimos no pasado. Déixeme reiniciar este, unha vez máis, de xeito que eu poida apuntar algo máis para fóra, ben. Neste caso, é agora me preguntar, de novo, para un número, o cal Eu vou, unha vez máis, entrar. Pero esta vez, eu vou entrar en un número maior para que o loop for ha interactuar máis veces. Neste caso, eu vou para introducir un valor de 11. Agora, de novo, porque eu tiña definido un punto de interrupción na liña 15, vai destacar esa liña. Podemos ver que o noso número 11 é correctamente representados nos locais variables. Pasando por riba diso, podemos agora mira o que acontece ao seu valor de i a medida que proseguimos dentro deste loop. É incrementado cada vez que chegar ao cumio do que para loop. Agora, unha das cousas que poden ser útil para facer durante a execución deste programa é para min, en realidade, cambiar o variables midstream para ver o que pasa co meu programa. Neste caso, podo realmente prema dúas veces o valor. Teña en conta que pasa a ser un campo de texto. Agora podo entrar diferente Valorados completamente para ver como o meu programa compórtase cando eu mudei esta variable. Agora, neste caso, a variable i agora contén o valor 10. Pero o programa aínda é fixo unha pausa na execución. Cando pasar por riba, vexo que a valor i, onde entrei como 10, non é maior que o valor de un, o que inmediatamente fai que o loop for para deter a execución. Agora que non é o único polo que faría quere modificar a variable no lugar. Pode realmente queren para tratar de modificalo para que poida continuar execución dun ciclo ou para que poida modificar algún valor antes atinxe algún conxunto específico de aritmética que está a piques de realizar. Polo tanto, agora que realmente cambiar a valor de i que o programa estaba en execución, que causou o loop for para saír prematuramente, porque, de súpeto, eu Pasou a ser maior que o valor de nun, o que significa que este bucle non se necesita para ser executado. Ademais, el pasou a ser o caso que nós cambiamos o valor de i cando a liña 17 foi destaque, que foi o punto no tempo para que a execución do bucle foi, de feito, está a ser avaliado. Se eu tivese cambiado o valor da i nunha liña distinta, digamos 19, teriamos visto diferente comportamento porque liña 19 sería executar antes do loop condición foi reavaliada. Agora, neste momento, eu estou de novo, a finais deste programa. E podo permitir que iso siga facer que o meu programa para saír suposto. Pero hai un par de cousas que son importantes para sacar dende esta discusión especial. Debe avaliar súas propias suposicións sobre como o código debe estar comportándose. Cada vez que pensar que algunha peza de código que sabe pasa para traballar, que pode ser unha bandeira vermella para ir para atrás e avaliar, e ter a certeza que a súa asunción de como que o código está funcionando é realmente verdade de como é expresa no seu código fonte. Pero aínda máis a cuestión era, cando estamos usando o depurador, pode pór puntos de interrupción en diferentes liñas de código, o que fará que o depurador deter a execución en cada unha destas liñas para que poida avaliar a memoria ou incluso cambia-lo no lugar. E, de novo, lembre que pode crear varios puntos de interrupción para que Tamén pode retomar a execución, pule ao longo de grandes porcións de código, e que vai deixar automaticamente o próximo punto de quebra. Hai realmente máis avanzado recursos do depurador, así. Pero nós imos ter que encamiñar-lo para algúns vídeos seguintes a fin de que realmente provocar unha separación como para usar estas funcións específicas. Por agora, grazas moito para ver. E boa sorte depuración.