C++. I have decades of experience with gdb, but in practice I almost always prefer to use prints. I think this is because my particular development environment makes prints really, really effective.
My build system automatically rebuilds my code and reruns all tests immediately upon me saving a file. So I sit with the test output open in one window and the code in another. I add a print statement, save, and a few seconds later, I see it in my output log. No need to even move focus out of my editor frame.
I find that for most purposes, this is much faster and more powerful than trying to use a debugger. I don't have to switch workflows between code editing and debugging. I get to probe the state from anywhere in the execution timeline, not just one breakpoint at a time.
Of course, this requires that whatever I'm debugging is reproducible in an automated test that runs fast (within seconds). This approach doesn't work nearly as well for anything that requires interacting with the program. But I mostly work on lower-level infrastructure and libraries that are highly test-driven and non-interactive, so it works out.
A few superficial things that help this workflow:
- I have a dedicated macro, KJ_DBG(), for debug prints, so I can easily stop myself from accidentally committing debug prints.
- The macro is optimized for debugging. If I write `KJ_DBG(x, y, z)` I'll get a log message saying "x = <value>; y = <value>; z = <value>" -- no need to waste time writing a format string.
- `KJ_DBG(kj::getStackTrace())` dumps the call stack trace, `kj::getAsyncTrace()` traces async event callbacks, etc.