¿Cómo usar @breakpoint en desarrollo?

¿Cómo usar @breakpoint en desarrollo?

Uso de @breakpoint en Zig

El compilador de Zig incluye una herramienta muy útil para depurar código de forma rápida y sencilla: el builtin @breakpoint. Este pequeño helper permite detener la ejecución del programa en cualquier punto, siempre que esté conectado un depurador como GDB, LLDB o VS Code. A diferencia de las impresiones de std.debug.print, @breakpoint interrumpe inmediatamente la ejecución, lo que facilita la inspección del estado interno.

¿Qué es @breakpoint?

@breakpoint es una función integrada del lenguaje que, cuando se ejecuta, envía una señal al depurador para que detenga el flujo de control. No tiene argumentos y devuelve void. Si no se está ejecutando bajo un depurador, la llamada simplemente no provoca ningún efecto visible.

Ventajas de usar @breakpoint

  • Detención inmediata del flujo de ejecución.
  • No requiere cambiar la salida estándar del programa.
  • Funciona en cualquier plataforma soportada por Zig.
  • Se puede eliminar de forma automática en compilaciones sin depurador, reduciendo el sobrepeso.

Cómo insertar un breakpoint

La sintaxis es muy directa: basta con colocar @breakpoint(); (o @breakpoint;) dentro del código donde se desea interrumpir la ejecución. A continuación se muestra un ejemplo minimalista:

// main.zig
const std = @import("std");

pub fn main() void {
    // Se entra en la función principal.
    std.debug.print("Inicio del programa\n", .{});

    // Punto de interrupción: el depurador se activará aquí.
    @breakpoint();

    std.debug.print("Continúa la ejecución después del breakpoint\n", .{});
}

En la línea 9, el depurador se activa. Si se ejecuta el programa bajo GDB, se mostrará la línea 9 como punto de parada y se podrá inspeccionar cualquier variable local o el stack.

Ejemplo práctico: depuración de una función recursiva

Supongamos que queremos depurar la función que calcula el factorial de un número. Insertaremos un breakpoint dentro del caso recursivo para ver el estado de la pila en cada llamada.

// factorial.zig
const std = @import("std");

// Función que calcula el factorial de manera recursiva.
fn factorial(n: u32) u64 {
    // Base de la recursión: factorial de 0 o 1 es 1.
    if (n == 0 or n == 1) {
        return 1;
    }

    // Breakpoint para inspeccionar valores durante la recursión.
    @breakpoint();

    // Llamada recursiva.
    return @intCast(u64, n) * factorial(n - 1);
}

pub fn main() void {
    const num = 5;
    std.debug.print("Factorial de {} es {}\n", .{ num, factorial(num) });
}
  • Línea 4: Declaración de la función factorial.
  • Línea 8: Condición base para terminar la recursión.
  • Línea 13: @breakpoint() que interrumpe en cada llamada recursiva.
  • Línea 16: Llamada recursiva que multiplica el resultado.
  • Línea 22-24: Función main que muestra el resultado final.

Al ejecutar zig build run bajo un depurador, se detendrá cada vez que factorial sea llamado, permitiendo observar los valores de n y el stack en cada nivel.

Usar @breakpoint en ciclos y condiciones

Los breakpoints son útiles para inspeccionar estados dentro de bucles o condiciones complejas. Veamos un ejemplo donde queremos localizar un error

Comments

No comments yet. Why don’t you start the discussion?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *