C++ Debugging Tips: How to Quickly Locate Issues with GDB

Writing code inevitably leads to bugs. Using print statements to check values? That’s too basic! Today, let’s have a good talk about using

GDB, the debugging tool. Don’t be fooled by its simple interface; its debugging capabilities are truly powerful!

What is GDB?

Simply put, GDB is a command-line debugging tool that allows you to pause program execution, inspect variables, and step through code execution. Imagine pressing the pause button while playing a game, allowing you to slowly observe the status of each character in the game; that’s essentially what it does.

int main() {
    int x = 10;
    int y = 20;
    int result = x + y;  // Want to see the value of this line when executed?
    return 0;
}

What to Prepare Before Debugging

🔔 Friendly reminder: Remember to compile with the <span>-g</span> option; otherwise, GDB won’t see anything!

g++ -g test.cpp -o test
gdb ./test

Common Debugging Commands

Setting breakpoints is the most fundamental operation in debugging, like setting up a roadblock on the code path:

break 10  # Set a breakpoint at line 10
break main  # Set a breakpoint at the main function

Once the program is running, you can use these commands:

run  # Start execution
next  # Next line (do not enter function)
step  # Step into (will enter function)
continue  # Continue execution until the next breakpoint
print x  # Print the value of variable x

Inspecting Memory and Variables

Sometimes just looking at surface values isn’t enough; you also need to investigate what’s stored in memory:

x/16xb ptr  # Display 16 bytes pointed to by ptr in hex
watch var  # Monitor changes to variable var

Multithreaded Debugging

Most programs written today are multithreaded, and GDB handles that too:

#include <thread>

void worker() {
    int count = 0;
    while(count < 1000) {
        count++;
    }
}

int main() {
    std::thread t1(worker);
    std::thread t2(worker);
    t1.join();
    t2.join();
    return 0;
}

While debugging, you can use these commands:

info threads  # Display all threads
thread 2  # Switch to thread 2

Conditional Breakpoints and Logging

🚀 Advanced tip: Conditional breakpoints are super useful, for example, only stopping when a certain value changes:

break 20 if x > 100  # Trigger breakpoint only if x>100
commands  # Set commands to execute when breakpoint is hit
> print x
> continue
> end

About Core Files

💡 Tip: When a program crashes, set it to generate a core file, so you can analyze the issue later with GDB:

ulimit -c unlimited  # Allow core file generation
gdb program core  # Analyze the core file

Graphical Interfaces

Not comfortable with the command line? Try these graphical interfaces:

  • DDD
  • Nemiver
  • Eclipse’s CDT plugin

However, I find the command line more efficient; just a couple of keystrokes and you’re done, plus it’s less hassle.

Practical Tips

Take notes while debugging, documenting the issues encountered and their solutions. Debugging is also a skill; practice is key to mastering it. When facing a stubborn bug, analyze calmly and avoid rushing to change the code.

🎯 Remember while debugging:

  • Clearly think through the expected results
  • Find the minimal reproduction steps for the program anomaly
  • Keep the input data that can reproduce the issue safe

Debugging is like a decryption game; with the right tools and techniques, debugging can also become quite interesting!

Leave a Comment