[? 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.