Debugging
| Compile for debug | |
| Strategic prints | |
| gdb basics | |
| Halve the code |
Compile for debug
A debug build turns on extra checks and turns off optimization so the program behaves in a simple and predictable way.
Compile with -g and -O0 plus -fcheck=all and -Wall -Wextra while hunting a bug. The binary runs slower but reports bounds errors and suspicious code early.
gfortran -g -O0 -fcheck=all -Wall -Wextra main.f90 -o main_dbg
main_dbg built with checks and no optimization
Keep one debug build next to the fast build. Reproduce the failure in the debug binary first, because the error message often points at the exact line.
Strategic prints
Small labeled prints show values at procedure boundaries without flooding the screen.
Print inputs and results with a text label, then remove the lines after the fix. Two clear lines beat twenty unclear ones.
program debug_print
implicit none
integer :: i
real :: x
x = 0.0
do i = 1, 5
x = x + real(i)
print *, "i =", i, "x =", x
end do
end program debug_print
gdb basics
The gdb debugger lets you pause a program, inspect variables, and step line by line. Think of it as prints on demand.
The core ideas are breakpoint to mark a stop line, run to start, print to show a value, next to move one line, and quit to leave. Learn these five first.
gdb ./main_dbg
set breakpoint, run, print a variable, step to the next line
Always debug the binary built with -g. Without debug symbols the debugger shows addresses instead of variable names and line numbers.
Halve the code
When nothing is obvious, halve the suspect area. Disable half the logic, rerun, and keep the half that still fails.
Each run removes half the mystery, so even a large file shrinks to one faulty loop in a few steps.
program halve_demo
implicit none
integer :: vals(4)
integer :: k
vals = [1, 2, 3, 4]
do k = 1, 4
print *, "k =", k, "v =", vals(k)
end do
end program halve_demo
Next: C interoperability
Article author: Arthur Isaev