[? DAN ARMADARAS:?] Hola, Estoy [? Dan Armadaras?]. Hoy, vamos a se busca en la depuración. No sólo vamos a hablar de algunas técnicas, sino que también vamos a mirar algunas de las características contenidas dentro del IDE CS50 que permiten depurar fácilmente un programa. Sólo un ejemplo de algo que puede salir mal y de hecho es algo que ya hemos visto antes. En este caso, este es un programa C que acepta un número entero de usuario, lo divide por dos, y proporciona la salida de nuevo al usuario. Ahora de lo que hemos visto anteriormente en conferencias, sabemos que esto va a causar tipos específicos de problemas de división cuando tenemos números impares. En concreto, sólo tendremos que tiramos nada después de la coma decimal. Ahora, sabemos que este pasa a ser el caso. Y si corremos, podemos confirmar nuestras sospechas, primero, por la compilación. Y luego, corriendo y entrar en un número impar. Esto no es nada nuevo. Pero esto es en realidad un ejemplo de un error que puede existir dentro de un programa más amplio que se convierte en más difícil de rastrear. A pesar de que sabemos cuál es el problema es decir, el verdadero quid de la cuestión podría tratar de identificar específicamente donde se produce el error, identificar lo que ese problema es, y luego arreglarlo. Así que ofrecer esto como un ejemplo de lo que podría ser algo que ya sabemos, pero puede ser enterrado dentro de otros elementos del código. Por lo tanto la apertura de esta otra fuente archivo de código como un ejemplo, este problema de división es ahora parte de un programa más amplio. Aún podría ser un poco poco artificial, y nosotros podría ser capaz de facilidad identificarlo, especialmente ya que sólo estamos discutiendo esto. Pero podemos imaginar que esta problema puede existir en una escala más grande. Si compilo esto y ahora ejecutarlo, introduzca un número impar, podemos ver que no obtenemos precisamente la salida que podemos haber esperado. En este caso particular, podríamos decir que nos quieren contar todos los números desde uno hasta algún número específico. Y podemos ver que tener una variedad de temas aquí si estamos salida, simplemente, 0 y 1 cuando proporcionamos una entrada de 5. Así que ya sabemos que hay un problema aquí. Pero no podemos saber con precisión donde este problema realmente existe. Ahora una de las formas en que podemos tratar de solucionar este problema es algo que hemos ya se ha introducido a. Sólo podemos usarlo en una escala más grande. En la línea 14, que tenemos esta función printf, lo que nos permite imprimir el estado de varias piezas de información. Y esto es algo que usted debe aprovechar dentro de su programa para tratar de averiguar exactamente lo que es sucediendo en diversas líneas de código. Así que incluso si este no es el salida final que en realidad querer producir de este programa, todavía podrían tener cierta depuración declaraciones donde nos puede tratar de averiguar exactamente lo que está sucediendo dentro de nuestro código. Así que en este caso, lo haré printf con la etiqueta de depuración. En este caso, esto es sólo una cadena de depuración que estoy hasta desagradable para que se convierta muy claro en la salida de mi código qué es lo que quiero mostrar. Y aquí el número de salida que hemos calculado. En este caso, podría diga de forma precisa lo que está ocurriendo antes y después de un cálculo específico. Así que yo podría utilizar un printf antes y después de esa línea de código. En este caso, podría incluso que sea un poco más clara diciendo depuración antes y depuración después de tanto que yo no confundo a mí mismo con múltiples líneas que parecen idénticos. Ahora bien, si a compilar y ejecutar este ella, entrar un número como de cinco más, podemos ver que tenemos ahora de salida antes y después de y encontramos que no hemos hecho una clara división o transparente que tiene el número que en realidad queremos hacer. Ahora bien, en este caso, se trata de no es realmente una salida clara. En realidad no es un resultado claro que queremos salir de este programa en particular. Y esto es, de nuevo, un poco artificial. Pero, tal vez, una de las cosas que que podríamos hacer si la especificación dijo que queremos dividir esto 2 y añadir 1-- por lo que en otras palabras, queremos redondear up-- continuación podríamos saber que pudimos hacer esa cosa en particular, en este caso. Ahora, aquí sabemos que seremos capaz de sumar 1 a nuestro número reducido a la mitad. Vamos a recompilar este y confirmar que esta se comporta de la manera que queremos. Podemos ver que ahora antes de que tener, tenemos el número 5. Después de tener, tenemos el número 3, que de acuerdo con nuestra especificación, es lo que queríamos hacer. Pero si nos fijamos en el salida de aquí, podemos ver que podríamos tener otra bug por completo, que es que estamos empezando nuestra cuenta desde 0. Ahora, de nuevo, esto es algo que hemos visto en el pasado y podemos fijar con bastante facilidad. Pero en este caso, También tenía la ventaja de utilizar la instrucción printf directamente en el interior del bucle for saber con precisión dónde que el error estaba ocurriendo. Declaraciones Así printf son muy útil para ayudar a determinar dónde, precisamente en su código fuente, se está produciendo un error específico. Y también es importante tener en cuenta que, como estamos escribiendo código, podríamos tener supuestos sobre el estado de un programa. O puede ser que tengamos supuestos sobre qué parte del programa es realmente correcto o incorrecto cuando más adelante a medida que construimos en ese programa y que sea parte de un complejo y más grande programa que nos damos cuenta de que algún aspecto de que es en realidad buggy. El uso de printf realmente puede ayudar delimitar e identificar las regiones de un programa que no puede se comporta exactamente de la manera que nosotros esperar que, con base en nuestras suposiciones. Pero hay otras herramientas disponibles, así, que nos permiten tratar de entender dónde se está produciendo un error y también, específicamente, qué cosas están sucediendo dentro del programa. Así que usando printf es muy cuando queremos útil para identificar las áreas específicas de un programa que tiene algunos errores. Pero también se convierte aburrido después de un tiempo. En este caso, se trata de una programa relativamente simple con sólo una o dos variables. Y se hace muy fácil para nosotros imprimir el valor de esas variables en el contexto del programa más grande. Pero podríamos tener un diferente programa que tiene muchas variables. Y puede no ser bastante tan fácil de usar printf para tratar de evaluar lo que está sucediendo a cada una de esas variables ya que el programa se está ejecutando. Hay un programa que existe llamado un programa depurador. En este caso, el que lo haremos uso es el depurador de GNU, o GDB, que nos permite inspeccionar el interior funcionamiento de un programa en una forma mucho más manera detallada. De hecho, podemos ejecutar BGF desde la línea de comandos aquí simplemente escribiendo el BGF y la comandos que queremos depurar. En este caso, contar. Ahora bien, en este caso, podemos ver que nos lleva a un mensaje que dice GDB. Y podemos realidad ejecutar comandos de GDB para comenzar realmente la ejecución de la programa, detenerlo en ciertos puntos, evaluar las variables y inspeccionar las variables que existir en el estado del programa en ese momento particular, y así sucesivamente y así sucesivamente. Proporciona una gran cantidad de energía para nosotros. Pero da la casualidad que el IDE CS50 también proporciona una interfaz gráfica de usuario o de un usuario interfaz para que GDB nos permite hacer esto sin necesidad la interfaz de línea de comandos en absoluto o en todo incluso. La forma en que yo pueda acceder a esa es mediante el botón de depuración en la parte superior del IDE CS50. Ahora bien, en el pasado, lo que tenemos visto es que usamos el comando line para compilar y ejecutar un programa. El botón de depuración hace ambos de esos pasos. Pero también se abre la pestaña depurador en el extremo derecho que nos permite inspeccionar una variedad de las propiedades del programa ya que se está ejecutando. Si hago clic depuración, en este caso, se abrirá una nueva pestaña en la consola ventana en la parte inferior. Y se puede ver que esta ficha tiene algo de información en la parte superior. Y podemos ignorar en gran medida esto. Pero una de las cosas que queremos notar es que emite lo mismo que nosotros obtendría si tratamos de hacer funcionar el el programa de C en la ventana de terminal. Aquí, podemos ver que se está ejecutando sonido metálico, y tiene una variedad de banderas, y se está recopilando nuestro archivo count.c, que fue la ficha seleccionada en el momento que me golpeó de depuración. Así que esto es muy útil porque ahora con este botón de depuración, podemos recopilar de forma simultánea y después ejecutar el programa que en realidad que desee ejecutar. Uno de los indicadores que se importante, en este caso, que en realidad hemos estado usando para el tiempo más largo sino que también acaba de hacer un poco de la mano agitando [inaudible], que es esta de aquí. En clang, dice -ggdb3. En este caso, lo que somos diciendo sonido metálico, nuestro compilador, es que queremos compilar nuestro programa. Pero también proporcionar lo que son llamada información de símbolos para que el compilador en realidad tiene acceso a una gran cantidad de la información subyacente contenida dentro del programa. Más específicamente, el número de las funciones que tengo, los nombres de las funciones, las variables, los tipos que esas variables son, y una variedad de otras cosas que ayudan a que el depurador realizar su operación. Ahora hay algo más eso es importante mencionar cuando estamos discutiendo en ejecución un programa de esta manera. Observe que no tiene realidad criado una nueva pestaña en nuestra consola a lo largo de la parte inferior. Ya no tenemos que interactuar directamente con la ventana de terminal. Pero esta nueva pestaña es en realidad una ventana de terminal. Sólo es específico para el funcionamiento programa que hemos creado. Observe que en la parte inferior, en combinación con alguna salida por clang el compilador y el BGF, que podemos ignorar en gran medida, que en realidad muestra la salida de nuestro programa en la parte inferior. Ahora es importante tener en cuenta que esta en realidad una ventana le mostrará la salida de su programa pero también puede aceptar la entrada para ese programa, también. Así nota que indica Por favor, introduzca un número, que es la misma salida que teníamos tenía en la ventana de terminal antes. Pero se muestra ahora en esta nueva pestaña. Me puede introducir un número. Y lo hará realidad función que esperamos mostrándonos nuestra depuración, la producción, la salida que podría ser con errores, como hemos visto antes. Y en la parte inferior, se en realidad tiene una salida adicional del PIB sólo decir que este programa se ha completado. Ahora bien, como se vio en este en particular carrera a través de, no era particularmente útil porque incluso a pesar de que había llegado el menú depurador arriba, esto era todavía un programa en ejecución. En ningún momento hizo realidad detener la ejecución para nosotros ser capaz de inspeccionar todos las variables contenidas dentro. Hay algo más que tenemos que hacer para para obtener GDB reconocer que queremos para detener la ejecución del programa y no sólo permitir que se proceda normalmente como lo haríamos en cualquier otro caso. Con el fin de detener la ejecución, en algún línea específica, tenemos que crear lo que es llamado un punto de quiebre. Y un punto de quiebre se crea con mucha facilidad en este CS50 IDE tomando el puntero del ratón y haciendo clic directamente a la izquierda de un número de línea específico. Una vez que lo hago, un punto rojo aparece, que indica que esa línea es ahora un punto de quiebre. Y la próxima vez que corro GDB, que se detendrá la ejecución en ese punto de ruptura cuando llega a esa línea de código. Ahora bien, este es un importante es darse cuenta que no es necesariamente el caso de que cada línea de código es realmente accesible. Si tuviera que crear una función aquí, por ejemplo-- vacío F-- y acaba de hacer una línea de impresión aquí-- hola mundo-- si no vuelvo a llamar a esta función, será el caso de que, si me puse un punto de descanso aquí, la función nunca se llamará. Y por lo tanto, este en particular punto de quiebre será en realidad nunca hacer una pausa ejecución del programa. Así que digamos que yo creo correctamente un punto de quiebre en alguna línea de código que realmente se ejecuta. Ahora bien, en este caso, este es el primera línea de la función principal. Así que sin duda será el caso que, tan pronto como empiezo ejecución, se llegará a la primera línea. GDB se detendrá la ejecución. Y luego, voy a ser capaz de interactuar con el depurador. Puede establecer varias líneas como puntos de ruptura, si usted desea. También podemos crear una línea hacia arriba aquí en este segmento de código eso nunca se alcanzará. Y también podemos establecer uno más adelante. La razón de que lo haríamos querer hacer esto vamos a entrar en un poco más detalle en un momento. Así que por ahora, permítanme inhabilito estos puntos de quiebre adicionales para que podamos ver lo que sucede cuando tengo una sola ruptura punto de mi programa. He hecho algunos cambios en este programa. Así que tengo que guardarlo. Voy a hacer clic de depuración para que yo pueda comenzar la compilación y después ejecución del depurador. Vamos a ver que, después de momentos, los línea que hemos seleccionado como el descanso punto se resalta en amarillo. También podemos notar que en el superior derecha del panel de depuración de que el icono de pausa se ha convertido en un pequeño icono de reproducción. Esto significa que tenemos que hacer una pausa ejecución, en este caso particular. Y golpear el botón de reproducción se nos permite reanudar la ejecución en ese punto específico. Observe que hay un par de otros botones disponibles en este panel de depuración, así como. Pasar por encima, lo que me permite ejecutar que una línea de código y pasar por encima de esa línea a la siguiente, que, en este caso, que significaría que el printf se ejecuta comunicado. Y a continuación, hará una pausa la ejecución de la línea 13, como tal. Y hay también un paso en función, que es útil si he creado otra funciones en el código fuente en otros lugares. Y quiero entrar en esas funciones en lugar de ejecutar esa función como un todo. Pero vamos a ver más en el paso en función en un momento. Ahora note algunas otras cosas que realmente existir dentro de este panel de depuración. Tenemos este panel llamado Pila de llamadas, lo que nos muestra dónde exactamente que somos. En este caso, estamos dentro de la función principal. Nuestro script se llama count.c. Y nos toca estar en línea 13, columna uno, que es precisamente lo que la región resaltada del código fuente indica, también. Ahora note que esto demuestra también en la sección variable local todas las variables que existir dentro de esta función. Es importante tener en cuenta que todas las variables aparecerá en esta variable local sección dentro de una función, incluso antes de que se definen. Podemos ver aquí que tenemos una variable llamada num, tiene un valor predeterminado de 0, y es de tipo int. Ahora antes de que realmente inicializamos todas estas variables, no estamos necesariamente garantizado para ver un valor de 0. Y dependiendo de otras ejecuciones que ha realizado y el estado de su memoria cuando en realidad se ejecuta este programa, usted podría encontrar que usted no ven los valores de 0 y, en cambio, algunos otros números de locos. Pero no te preocupes por eso. No va a ser relevante hasta que realmente inicializar el valor. Ahora bien, en este caso, podemos ver que He realizado algunas salidas. Y estoy, ahora mismo, detuve la ejecución. Pero en este caso, lo Tengo muchas ganas de hacer es dar un paso ahora sobre esta línea de código para que pueda realmente consultar el usuario para ese int que queremos utilizar en nuestro programa. Ahora bien, en este caso, cuando Golpeé pasar por encima, previo aviso que la pausa o más bien la reanudación botón ha cambiado a este botón Pausa ya que este código se ejecuta en realidad. Que esta pasando en este momento es que se trata esperando por nosotros para introducir alguna información como podemos ver por nuestro texto de salida en la parte inferior. Así que ahora mismo, esto es en realidad no se detuvo, a pesar de que, en cierto modo, parece ser porque nada está sucediendo. Pero da la casualidad de que en mi caso concreto en la línea 13, Estoy esperando a la entrada del usuario. Y así BGF no es capaz de inspeccionar un programa a medida que se está ejecutando. Ahora, la próxima vez que entro en alguna input-- así que voy a entrar en ese número 5, como hemos visto en el past-- pulsa Intro, y nosotros notar que, inmediatamente, pausas GDB y, de nuevo, se destaca la siguiente línea. Pero nótese que ahora, como un resultado de nuestra ingresar un valor, hemos actualizado ese valor en el interior de nuestras variables locales, que es muy útil saber con precisión lo que ese número era en la memoria. Ahora puedo permitir que este programa continúe jugando hasta el final de su ejecución pulsando Reanudar. Podemos ver que muy rápidamente hace el acabado programa en ejecución con la misma salida que nos tenido antes, el depurador se cierra, y ahora este programa se ha detenido por completo. Muestro que sólo para el efectos de ver lo que que sucede cuando en realidad nos golpeamos Reanudar. Pero que en realidad vamos a quiero volver a este programa para que podamos tratar de depuración precisamente lo que está sucediendo. Ahora que estoy utilizando el depurador, me lo permite no necesita estas declaraciones de depuración printf. Así que podría eliminarlos como voy a hacer ahora acaba de regresar a nuestro código más simple que teníamos hace un momento. Ahora, cuando me ahorro el programar y ejecutarlo, será, de nuevo, ir a esa inicial romper el punto que yo tenía en la línea 11. Y voy a ser capaz de inspeccionar mi variables como lo quieren hacer. Lo que pasa es que esta parte no es muy interesante, Y sé que voy imprimir esta declaración. Por favor, introduzca un número. Y luego, sé que voy preguntar al usuario para ese número entero. Así que tal vez, yo en realidad quiero mover mi punto de romper un poco más abajo. Puede eliminar puntos de quiebre haciendo clic, de nuevo, directamente a la izquierda de ese número de línea. Ese punto rojo desaparecerá, indicando que ese punto de ruptura se ha ido. Ahora bien, en este caso, ejecución está en pausa. Y lo que no es en realidad va a reanudar en ese caso particular. Pero puedo configurar un descanso apuntar un poco más tarde. Y cuando Reanudo ahora mi código, se reanudará y contar el punto de que el punto de quiebre. Una vez más, me golpeó en Reanudar. No parece nada está sucediendo. Pero eso es porque mi código está a la espera para la entrada. Voy a introducir un número 5, pulse Enter, y Ahora se dio en el siguiente punto de ruptura. Ahora, en este caso, esta es la línea de código que, antes, sabíamos pasó a ser buggy. Así que vamos a evaluar lo que sucede en este punto particular en el tiempo. Cuando se resalta una línea, esta línea aún no ha sido ejecutado. Así que en este caso, podemos ver que tengo un número, que Tengo un entero llamado num que tiene un valor de 5. Y yo voy a realizar un poco de matemática en ese número. Si me paso más de eso, podemos notar que el valor de num ha cambiado de acuerdo con el aritmética que realmente hemos hecho. Y ahora que estamos dentro de este bucle o ahora que el bucle for sí está resaltado, vemos que tenemos una nueva variable i llamada que va a ser utilizado en ese bucle. Ahora recordar antes de que yo mencionó que a veces eres ir a ver algún tipo de locura números como predeterminado antes de ese número o esa variable es en realidad inicializado. Podemos ver que, precisamente, aquí en la esta variable llamada i, que no tiene sin embargo, ha inicializado en el momento de poner de relieve. Pero podemos ver que tiene un número que no íbamos realmente esperar. Eso está bien. ¡No se preocupe porque tenemos en realidad no inicializado ese número hasta que pasar por encima de esta línea y el valor i ha sido inicializado con el valor 1. Así que a ver que eso es en realidad el caso, vamos a pasar por encima. Ahora podemos ver que ese línea ha sido ejecutada. Y ahora estamos destacando esta línea printf. Y ahora podemos ver cómo nuestros valores de i y 3 he cambiado con el tiempo. Esto es muy útil para hacer, de hecho, es pasar por encima de las líneas en varias ocasiones. Y usted puede encontrar lo que realmente que sucede dentro de su bucle for y lo que le sucede a la las variables dentro de ese bucle for como que la ejecución del programa se produce un paso a la vez. Ahora, en este punto, pasó por encima de lo justo que ahora estoy al final de mi programa. Si me paso más de eso, lo hará de hecho cesar la ejecución como hemos visto en el pasado. Permítanme recomienzo esto, una vez más, por lo que que puedo señalar algo más, así como. En este caso, es ahora me pide, una vez más, para un número, el cual Yo, de nuevo, entrar. Pero esta vez, voy a entrar en un número más grande para que el bucle for iterará más veces. En este caso, me voy para introducir un valor de 11. Ahora, de nuevo porque me puse un punto de quiebre en la línea 15, se va a poner de relieve esa línea. Podemos ver que nuestro número 11 es correcta representado en nuestras variables locales. Pasando por encima de eso, podemos ahora observa lo que sucede a nuestro valor de i a medida que avancemos en el interior de este bucle. Se pone incrementa cada vez que llegar a la cima de ese bucle. Ahora una de las cosas que podría ser útil para hacer durante la ejecución de este programa es para mí realmente cambiar el medio de la corriente de variables para ver lo que pasa a mi programa. En este caso, no puedo realmente haga doble clic en el valor. Observe que se convierte en un campo de texto. Ahora puedo entrar en diferente valorar por completo para ver cómo se comporta mi programa cuando he cambiado esa variable. Ahora, en este caso, la variable i ahora contiene el valor 10. Pero el programa sigue siendo pausa en la ejecución. Cuando doy un paso más, veo que la i valor, que entré en el 10, no es mayor que el valor de num, que de inmediato hace que el bucle for para detener la ejecución. Ahora eso no es el único razón por la que lo haría querer modificar la variable en su lugar. Usted puede ser que realmente quiere para tratar de modificarlo para que puede continuar ejecución de un bucle o para que usted puede modificar algún valor antes de que se llega a un conjunto específico de la aritmética que está a punto de realizar. Así que ahora que en realidad cambiamos el valor de i que el programa se ejecuta, causó el bucle for para dejar de fumar prematuramente porque, de repente, me pasó a ser mayor que el valor de num, lo que significa que ese bucle for ya no es necesario para ser ejecutado. Además, pasó a ser el caso de que cambiamos el valor de i cuando se puso de relieve la línea 17, que era el punto en el tiempo para que la ejecución del bucle fue en realidad se está evaluando. Si yo hubiera cambiado el valor de i en una línea diferente, digo 19, habríamos visto diferente comportamiento porque la línea 19 lo haría haber ejecutado antes del bucle condición fue reevaluado. Ahora en este momento, estoy, de nuevo, al final de este programa. Y puedo permitir que esto continúe con permita que mi programa para dejar de fumar de forma natural. Pero hay un par de cosas que son importantes para llevar de esta discusión particular. Es necesario evaluar sus propias suposiciones acerca de cómo el código debe ser comportando. Cada vez que usted piensa que alguna pieza de código que sabes pasa a trabajar, que podría ser una bandera roja para ir atrás y evaluar, y asegúrese que asumido cómo ese código está funcionando es realmente fiel a la forma en que es expresado en el código fuente. Pero aún más a punto era, cuando estamos usando el depurador, usted puede poner puntos de ruptura en diferentes líneas de código, lo que provocará que el depurador detener la ejecución en cada una de esas líneas para que pueda evaluar la memoria o incluso cambiar en su lugar. Y de nuevo, recuerde que usted puede crear múltiples puntos de interrupción para que También puede reanudar la ejecución, omita sobre grandes porciones de código, y que va a hacer una pausa de forma automática en el siguiente punto de ruptura. De hecho, hay más avanzado características del depurador, también. Pero vamos a tener que hacer referencia que a algunos videos posteriores con el fin de burlarse de verdad, aparte de cómo utilizar esas funciones particulares. Por ahora, gracias mucho para ver. Y buena suerte depuración.