Aprendizaje de depuración de GDB (2): puntos de interrupción

depurador (sujeto experimental)

      #include <stdio.h>
      int main(void)
      {
        int sum = 0, i = 0;
        char input[5];
        while (1) {
                      scanf("%s", input);
                      for (i = 0; input[i] != '\0'; i++)
                              sum = sum*10 + input[i] - '0';
                      printf("input=%d\n", sum);
        }
        return 0;
      }

La función de este programa es: primero leer una cadena de números del teclado y almacenarlos en la entrada de matriz de caracteres, luego convertirlos en números enteros y almacenarlos en suma, y ​​luego imprimirlos, y el ciclo continúa así.

scanf("%s", input); La función de esta llamada es esperar a que el usuario ingrese una cadena y presione Entrar, scanf guarda la primera cadena que no está en blanco (no en blanco, tabulador, nueva línea) en la matriz de entrada , Y agrega automáticamente '\0' al final.

El siguiente bucle escanea la cadena de izquierda a derecha y suma cada número al resultado. Por ejemplo, ingrese "2345", el proceso de acumulación de bucle es (((0×10+2)×10+3)×10+ 4 )×10+5=2345.

Tenga en cuenta que el carácter '2' debe convertirse al valor entero 2 restando el código ASCII de '0'. Compilemos y ejecutemos el programa para ver qué está mal:

      $ gcc main.c -g -o main
      $ ./main
      123
      input=123
      234
      input=123234
   (按Ctrl+C组合键退出程序)
      $

Este es el fenómeno nuevamente, la primera vez es correcta, la segunda vez es incorrecta.

Pero en este programa, no olvidamos asignar un valor inicial, no solo a sum se le asigna un valor inicial, sino que incluso a i, que no necesita que se le asigne un valor inicial, se le asigna un valor inicial. Los lectores primero intentan ver si el código puede ver la causa del error. Vamos a depurar:

      $ gdb main
      ...
      (gdb) start
      Temporary breakpoint 1 at 0x804844d: file main.c, line 5.
      Starting program: /home/akaedu/main
      Temporary breakpoint 1, main () at main.c:5
      5               int sum = 0, i = 0;

Con la experiencia anterior, sum aparece como un sospechoso clave.Podemos usar el comando de visualización para mostrar el valor actual de sum cada vez que nos detengamos, y luego continuar hacia abajo:

      (gdb) display sum
      1: sum = 2637812
      (gdb) n
      9                     scanf("%s", input);
      1: sum = 0
      (gdb)(直接回车)
      123
      10                    for (i = 0; input[i] != '\0'; i++)
      1: sum = 0

El comando Undisplay puede cancelar la visualización de seguimiento. El número de la suma variable es 1, y el comando Undisplay 1 se puede utilizar para cancelar su visualización de seguimiento. No debería haber ningún problema con este ciclo, porque lo anterior imprime el resultado correcto en la primera entrada. Si no desea pasar por este ciclo paso a paso, puede usar el comando break (abreviado como b) para establecer un punto de interrupción (Breakpoint) en la línea 9:

      (gdb) l
      5               int sum = 0, i = 0;
      6               char input[5];
      7
      8               while (1) {
      9                       scanf("%s", input);
      10                      for (i = 0; input[i] != '\0'; i++)
      11                              sum = sum*10 + input[i] - '0';
      12                      printf("input=%d\n", sum);
      13              }
      14              return 0;
      (gdb) b 9
      Breakpoint 2 at 0x804845d: file main.c, line 9.

El parámetro del comando break también puede ser un nombre de función, lo que significa establecer un punto de interrupción al comienzo de una determinada función. Ahora use el comando continuar (abreviado como c) para ejecutar continuamente en lugar de un solo paso, y el programa se detendrá automáticamente cuando llegue al punto de interrupción, para que pueda detenerse al comienzo del siguiente ciclo:

      (gdb) c
      Continuing.
      input=123
      Breakpoint 2, main () at main.c:9
      9                       scanf("%s", input);
      1: sum = 123

Luego ingrese una nueva cadena lista para la conversión:

      (gdb) n
      234
      10                      for (i = 0; input[i] != '\0'; i++)
      1: sum = 123

El problema está expuesto, la nueva conversión debería comenzar a acumularse desde 0 nuevamente, y la suma ahora es 123, porque nuevo ciclo no puso a cero la suma .

(Entonces, este problema de análisis es tener su propio pensamiento avanzado y tener un juicio esperado sobre este resultado).

Se puede ver que los puntos de interrupción ayudan a omitir códigos rápidamente sin problemas, y luego caminar lentamente y analizar códigos problemáticos. "Puntos de interrupción más un solo paso" es el método básico para usar un depurador.

En cuanto a dónde establecer puntos de interrupción, cómo saber qué códigos se pueden omitir y qué códigos se deben recorrer lentamente, también se determina analizando y asumiendo el fenómeno del error. En el pasado, cuando usábamos printf para imprimir resultados intermedios, también Tuve que analizar dónde debería estar Inserte printf, qué resultados intermedios para imprimir, la idea básica de la depuración es la misma.

Se pueden establecer varios puntos de interrupción para una depuración, y el comando de información se puede usar para ver los puntos de interrupción que se han establecido:

      (gdb) b 12
      Breakpoint 3 at 0x80484b3: file main.c, line 12.
      (gdb) i breakpoints
      Num    Type          Disp Enb Address   What
      2      breakpoint    keep y   0x0804845d in main at main.c:9
        breakpoint already hit 1 time
      3      breakpoint    keep y   0x080484b3 in main at main.c:12

Cada punto de interrupción tiene un número, que se puede usar para especificar la eliminación de un punto de interrupción:

      (gdb) delete breakpoints 2
      (gdb) i breakpoints
      Num    Type          Disp Enb Address   What
      3      breakpoint    keep y   0x080484b3 in main at main.c:12

A veces, un punto de interrupción puede deshabilitarse en lugar de eliminarse si no se usa por el momento, de modo que pueda habilitarse directamente cuando desee usarlo en el futuro, sin tener que averiguar en qué línea debe establecerse el punto de interrupción. código de nuevo:

      (gdb) disable breakpoints 3
      (gdb) i breakpoints
      Num    Type          Disp Enb Address   What
      3      breakpoint    keep n   0x080484b3 in main at main.c:12
      (gdb) enable 3
      (gdb) i breakpoints
      Num    Type          Disp Enb Address   What
      3      breakpoint    keep y   0x080484b3 in main at main.c:12
      (gdb) delete breakpoints
      Delete all breakpoints? (y or n) y
      (gdb) i breakpoints
      No breakpoints or watchpoints.

La función de punto de interrupción de gdb es muy flexible. También puede configurar el punto de interrupción para que se active cuando se cumpla una determinada condición. Por ejemplo, seguimos configurando el punto de interrupción al comienzo del bucle, pero solo cuando la suma no es igual a 0. Luego use el comando ejecutar (abreviado como r) Vuelva a ejecutar continuamente desde el principio del programa:

      (gdb) break 9 if sum != 0
      Breakpoint 4 at 0x804845d: file main.c, line 9.
      (gdb) i breakpoints
      Num    Type          Disp Enb Address   What
      4      breakpoint    keep y   0x0804845d in main at main.c:9
          stop only if sum != 0
      (gdb) r
      The program being debugged has been started already.
      Start it from the beginning? (y or n) y
      Starting program: /home/akaedu/main
      123
      input=123
      Breakpoint 4, main () at main.c:9
      9             scanf("%s", input);
      1: sum = 123

El resultado es que no hay interrupción antes de que se ejecute el primer scanf, pero se interrumpe la segunda vez. Resuma los comandos gdb utilizados en esta sección, como se muestra en la siguiente tabla.

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_45264425/article/details/132289249
Recomendado
Clasificación