Digamos que no tiene un depurador disponible, ¿cuál sería un enfoque eficaz para el código de depuración que no funciona (como se esperaba)?
Digamos que no tiene un depurador disponible, ¿cuál sería un enfoque eficaz para el código de depuración que no funciona (como se esperaba)?
Respuestas:
Hay una serie de técnicas:
Inicio sesión. Si no tiene acceso a los archivos, inicie sesión en una consola serie o en cualquier dispositivo de salida disponible. Es una buena idea escribir siempre su código teniendo en cuenta el inicio de sesión, lo que permite una compilación condicional para diferentes niveles de registro, desde 'ninguno' hasta 'sobrebloqueado'.
Cortándolo Excluya las partes de su código alrededor de un punto sospechoso de error, uno por uno, y analice lo que ha hecho cuando el error desaparece.
Afirmaciones o contratos. Es una buena idea rellenar su código con afirmaciones desde el principio. No solo ayudan con la depuración, sino que también sirven como documentación adicional para su código.
Similar a 2. - varíe su entrada y reorganice el código a menos que el error desaparezca o cambie su comportamiento. A menudo es una buena idea jugar con varios niveles de optimización (si está codificando en C o C ++), ya que los errores relacionados con el puntero tienden a ser extremadamente volátiles en su comportamiento.
Una versión automatizada de 3. - use el código instrumentado, por ejemplo, ejecute el binario bajo valgrind.
Y, por supuesto, hay muchas más herramientas y trucos, dependiendo de la naturaleza de su entorno de ejecución y su código.
Busque un colega y explique el problema en detalle mientras recorre el código problemático paso a paso.
Con frecuencia, el acto de explicar deja en claro tanto a su colega como a usted mismo.
¿Existe un sistema de registro para administrar la salida del programa? ¿Hay al menos una consola para imprimir o archivos en los que pueda escribir? Usar consolas o archivos de registro es una forma de depurar sin un depurador. Proporcione al programa una entrada para que sepa cuál debería ser la salida, luego verifique que la salida funcione y asegúrese de que su registro le brinde muchos detalles del proceso. Luego intente con una entrada que dé la salida incorrecta. Con suerte, los registros le darán un rastro detallado de lo que salió mal.
Depende ¿Funcionó antes? Si el código que solía funcionar se rompió de repente, entonces debe examinar con mucho cuidado los cambios más recientes.
1) Haz lo que sea necesario para que el error sea 100% reproducible o lo más cercano posible al 100%
2) Rastree el problema, utilizando printf () u otro recurso de registro. Sin embargo, este es un arte y depende de la naturaleza del error.
Si no tiene absolutamente ninguna idea sobre la ubicación del error, pero por ejemplo sabe que una condición se vuelve falsa en algún momento (el estado del programa se rompió; llamémoslo IsBroken ()), puede hacer una búsqueda de profundización / partición para averiguar la ubicación del problema. Por ejemplo, registre el valor de isBroken () al principio al final de los métodos principales:
void doSomething (void)
{
printf("START doSomething() : %d\n", isBroken());
doFoo();
doBar();
printf("END doSomething() : %d\n", isBroken());
}
Si en el registro ves
START doSomething() : 0
END doSomething() : 1
Sabes que algo salió mal allí. Por lo tanto, elimine todos los demás códigos de registro y pruebe esta nueva versión:
void doSomething (void)
{
printf("START doSomething() : %d\n", isBroken());
doFoo();
printf("AFTER doFoo() : %d\n", isBroken());
doBar();
printf("END doSomething() : %d\n", isBroken());
}
Ahora en el registro puedes ver esto
START doSomething() : 0
AFTER doFoo() : 0
END doSomething() : 1
Entonces, ahora sabe que doBar () activa el error y puede repetir el procedimiento anterior en doBar (). Idealmente, reducirá el error a una sola línea.
Por supuesto, esto puede ayudarlo a revelar los síntomas del error y no la causa raíz ; por ejemplo, encuentra un puntero NULL que no debería ser NULL, pero ¿por qué? Luego puede volver a iniciar sesión, pero buscando una condición diferente "rota".
Si tiene un bloqueo en lugar de un estado roto, es más o menos lo mismo: la última línea del registro le da una pista de dónde se rompen las cosas.
Después de que las otras respuestas han fallado , siempre hay depuración de búsqueda binaria :
Nota: obviamente, esta técnica solo funciona si puede reproducir el problema de manera confiable.
"La herramienta de depuración más eficaz sigue siendo una reflexión cuidadosa, junto con declaraciones impresas juiciosas". - Brian Kernighan 'En su día puede haber sido cierto! El método más efectivo es mirar las pruebas unitarias, pero supongo que no tienes ninguna.
Depende del error.
Si el error es el tipo de 'por qué el código está haciendo A', entonces puede ser útil probar su propia comprensión del código que rodea la ubicación del 'código haciendo A'. Introduzca el nuevo código que espera generar nuevos errores (este código debería hacer que haga B, esto debería hacer que haga C). Por lo general, encuentro rápidamente algún código nuevo que genera un comportamiento que no espero. Luego espero pacientemente mientras mi mente construye un modelo mental actualizado del comportamiento del código para que el último cambio tenga sentido, y luego ese cambio del modelo mental generalmente explica por qué el código está haciendo A.
El segundo caso ha sido discutido en detalle aquí. Donde haya heredado el código, no tenga un modelo mental sólido de cómo funciona el código, no tenga una buena idea sobre la ubicación específica del error, etc. En este caso, desglose / división y- los métodos de conquista con declaraciones impresas pueden funcionar. Y si está bajo control de origen, asegúrese de verificar el cambio de código más reciente.
Ampliando la "La herramienta de depuración más efectiva sigue siendo un pensamiento cuidadoso, junto con declaraciones impresas juiciosamente colocadas".
Primero, intente reducir el momento en que ocurre el error. Haga que los síntomas observables por el usuario sean observables por el sistema. (por ejemplo, algunas cadenas cambian a galimatías, agregue un bucle que sondea el contenido del script y activa su depuración a medida que cambia). Por supuesto, si el error es un bloqueo, agregue el manejo por defecto.
Luego, intente reducir el hilo si el problema es con un entorno de subprocesos múltiples. Dé a cada hilo un identificador y bótelo cuando ocurra el error.
Una vez que tenga el hilo, espolvoree el código del hilo dado con printfs copiosamente para clavar el punto donde emerge.
Luego, regrese a donde ocurre la acción real que lo crea (la acción destructiva a menudo será bastante antes de que los datos dañados desencadenen el problema). Examine qué estructuras / variables ocurren cerca de la memoria, observe los bucles que los afectan, verifique los puntos donde se escribe el valor dañado.
Una vez que tenga el punto que estaba causando el problema, antes de solucionarlo, piense dos veces cuál debería ser el comportamiento correcto.