Lesson 31
Debugging with GDB
GDB (GNU Debugger) is a command-line debugging tool that allows you to pause a program, inspect variables, execute code one line at a time, examine memory, analyze crashes, and understand how your program behaves during execution. It is an essential tool for C programmers working on Linux applications, embedded systems, device drivers, and any project where printf() debugging is insufficient.
C Track
Save progress as you learn.
44 lessons
Lesson content
Debugging with GDB in C Programming: A Complete Beginner to Advanced Guide
What is GDB in C Programming?
Finding and fixing bugs is one of the most important skills for every C programmer. While printf() debugging works for small programs, it quickly becomes difficult as projects grow larger. This is where GDB (GNU Debugger) becomes an essential tool.
GDB (GNU Debugger) is a command-line debugging tool that allows you to pause a program, inspect variables, execute code one line at a time, examine memory, analyze crashes, and understand how your program behaves during execution.
Think of GDB as a pause-and-rewind remote control for your program. Instead of guessing where a bug is, you can stop execution at any point and inspect everything happening inside the program.
Why Does GDB Exist?
Without GDB, bugs are difficult to locate, developers rely on numerous printf() statements, crashes are hard to diagnose, and understanding program flow becomes challenging. With GDB, you can pause execution at any line, inspect variables and memory, step through code line by line, analyze segmentation faults, and debug complex applications efficiently.
Real-World Use Cases
GDB is widely used in:
- Linux application development
- Embedded systems
- Operating system development
- Device driver debugging
- Open-source C/C++ projects
- Network programming
- High-performance computing
Prerequisites
Before learning Debugging with GDB in C programming, you should understand:
- Basic C programming
- Functions
- Variables and data types
- Pointers
- Arrays
- Command-line basics
- GCC compilation
Core Concepts
What is GDB?
GDB is the GNU Debugger that lets you start a program under debugger control, pause execution, inspect and modify variable values, execute one line at a time, analyze crashes, and view the call stack.
Compiling with Debug Symbols
Always compile with the -g flag so GDB can map machine code back to your source code.
gcc -g -O0 -Wall -Wextra main.c -o main| Option | Purpose |
|---|---|
| `-g` | Include debug symbols |
| `-O0` | Disable optimization for easier debugging |
| `-Wall` | Enable common warnings |
| `-Wextra` | Enable additional warnings |
Starting GDB
gdb ./mainrunBreakpoints
A breakpoint tells GDB where to pause execution.
break main
break 25
info breakpoints
delete 1Stepping Through Code
| Command | Purpose |
|---|---|
| `next` | Execute current line without entering functions |
| `step` | Execute current line and enter functions |
| `continue` | Resume execution until next breakpoint |
| `finish` | Run until current function returns |
Viewing Variables
print count
display count
info localsExamining Memory
print ptr
x/10x ptrCall Stack
backtraceWatchpoints
A watchpoint pauses execution when a variable changes.
watch totalCode Examples
Example 1: Beginner – Debugging a Simple Program
#include <stdio.h> // Include standard input/output library
int main() // Program entry point
{
int number = 10; // Initialize variable
printf("%d\n", number); // Print value
return 0; // Exit successfully
}gcc -g simple.c -o simplegdb ./simple
break main
run
next
print number
continueExample 2: Intermediate – Finding a Logic Bug
#include <stdio.h> // Include standard I/O library
int main() // Program entry point
{
int sum = 0; // Initialize sum
for (int i = 1; i <= 5; i++) // Loop from 1 to 5
{
sum = i; // Bug: overwrites sum instead of accumulating
}
printf("%d\n", sum); // Print result
return 0; // Exit program
}break 8
run
display sum
nextExample 3: Intermediate – Debugging a Segmentation Fault
#include <stdio.h> // Standard I/O library
int main() // Program entry point
{
int *ptr = NULL; // Null pointer
*ptr = 100; // Causes segmentation fault
return 0; // Exit program
}gcc -g crash.c -o crashgdb ./crash
run
backtrace
print ptrExample 4: Advanced – Debugging Functions
#include <stdio.h> // Standard I/O library
int square(int x) // Function to compute square
{
return x * x; // Return square
}
int main() // Program entry point
{
int result = square(5); // Call function
printf("%d\n", result); // Print result
return 0; // Exit program
}break square
run
step
print x
finishExample 5: Advanced – Tracking Variable Changes with Watchpoints
#include <stdio.h> // Standard I/O library
int main() // Program entry point
{
int counter = 0; // Initialize counter
for(int i = 0; i < 5; i++) // Loop five times
{
counter += i; // Update counter
}
printf("%d\n", counter); // Print result
return 0; // Exit program
}watch counter
run
continueCommon Mistakes and Pitfalls
| Wrong | Correct |
|---|---|
| Compiling without -g | Compile using gcc -g |
| Using optimized builds while debugging | Use -O0 for easier debugging |
| Depending only on printf() | Use breakpoints and variable inspection |
| Forgetting to remove old breakpoints | Use delete or clear |
| Ignoring the call stack after crashes | Always check backtrace |
Wrong:
gcc main.c -o mainCorrect:
gcc -g -O0 -Wall -Wextra main.c -o mainBest Practices
- Compile with -g -O0 while debugging.
- Enable compiler warnings with -Wall -Wextra.
- Use breakpoints instead of excessive printf() statements.
- Inspect variables frequently using print and display.
- Use watchpoints to track unexpected changes.
- Analyze crashes with backtrace.
- Debug one issue at a time.
- Remove temporary breakpoints when finished.
- Learn GDB keyboard shortcuts to improve productivity.
- Combine GDB with tools like AddressSanitizer and Valgrind for memory-related bugs.
When NOT to Use This
While GDB is powerful, it may not be the best choice when:
- You only need quick logging output.
- Debugging timing-sensitive code where breakpoints alter behaviour.
- Working with highly optimized release binaries where variables may be optimized away.
- Performing performance profiling, where specialized profilers are better suited.
Summary / Key Takeaways
- GDB is the standard debugger for C and C++ programs.
- Always compile with -g and preferably -O0.
- Breakpoints pause execution at specific locations.
- step enters functions, while next executes the current line without entering functions.
- Use print, display, and info locals to inspect variables.
- Watchpoints detect when variables change.
- backtrace helps identify the source of crashes.
- GDB significantly reduces debugging time compared to relying solely on printf().
FAQ About Debugging with GDB in C
1. What is GDB in C programming?
GDB (GNU Debugger) is a tool that allows developers to run, pause, inspect, and debug C programs interactively.
2. Why should I compile with -g?
The -g option includes debugging symbols so GDB can display source code, variable names, and line numbers instead of only machine instructions.
3. What is the difference between step and next?
step executes the current line and enters called functions. next executes the current line but skips over function calls.
4. What is a breakpoint?
A breakpoint is a marker that tells GDB to pause program execution at a specific line or function so you can inspect the program's state.
5. Can GDB fix bugs automatically?
No. GDB helps you identify and understand bugs, but it is the programmer's responsibility to modify the source code and correct the issue.