7 ms·
On a general note, I would recommend any new (and experienced!) programmers to master the debugging tools of their ecosystem. I've seen countless experienced de
by rkharsan64 2y ago
On a general note, I would recommend any new (and experienced!) programmers to master the debugging tools of their ecosystem. I've seen countless experienced developers use printf-based debugging and waste hourse debugging something which could've been easily figured out by setting a breakpoint and stepping through your code. This is also a good way to understand code you're unfamiliar with.
This is one area where I believe a GUI tool is so much better: I can hover over variable names to view their values, expand and collapse parts of a nested structure, edit values easily, and follow execution in the same environment I write my code in.
Sure, it doesn't help much for some scenarios (one I've heard people mention is multithreaded code, where logs are better?), but for most people it's not that far from a superpower.
- VyseofArcadia 2y agoBut also, experienced programmers should never forget their printf debugging roots. I was debugging something earlier this week that was hit like a hundred times in a tight loop. After the first dozen or so times I told gdb to continue, I realized, wait, this will be faster if I just fprintf some relevant information to a file. Sure enough the file pointed me in the right direction, and I was able to go back and get fancy with "disp" and "cond" and hit that breakpoint only when I needed to.
- mark_undoio 2y agoYou could also use GDB's Dynamic Printf (https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynamic-Printf.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynam...) to do the logging directly from GDB. Essentially you set it like a breakpoint (attaching a printf style string to a code location) and then just "continue" until you've gathered what you want.
- VyseofArcadia 2y agoOh sweet. I didn't know about that. I will be adding that to my toolbox.
- cevn 2y agoIn Jetbrains you can also do a Conditional breakpoint to active only if i=100 or something.
- VyseofArcadia 2y agoWell yeah, but I didn't know I wanted i = 100 until I had examined the fprintf output.
- gregthelaw 2y agoYou need a time travelling debugger! https://undo.io/ https://undo.io/ https://rr-project.org/ https://rr-project.org/ https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/time-travel-debugging-overview https://learn.microsoft.com/en-us/windows-hardware/drivers/d...
- amlib 2y agoWhat happens if the loop executes some non-idempotent calls? I guess printf debug still has some value :)
- mark_undoio 2y ago> What happens if the loop executes some non-idempotent calls? I guess printf debug still has some value :) Then they'll do the same thing when you replay. Non-idempotent system calls are tricky because they interact with the outside world - but that's still OK. In Time Travel Debug, the process you're debugging is essentially in the Matrix. When it's being recorded everything acts as normal (and it'll see the real results of those non-idempotent calls). When it's being debugged, any interaction with the outside system is prevented and replaced with the behaviour we saw at record time. It'll still think it's doing the non-idempotent calls, they just won't change (or depend upon) the state of the rest of the system.
- slashdave 2y agoUm, is it okay to admit, as an "experienced" programmer, that I often resort to print statements? I mean, compilers are just so darn fast these days. Another trick: for rare circumstances, code whatever complicated logic is needed to isolate the bug in order to issue a print statement, then use the debugger to break on that print statement.
- underdeserver 2y agoI would add to that that in most scenarios where people think debugging doesn't help or won't work - it can. Running inside Docker, multithreaded, multiprocessed, all can be debugged with a little effort. Most often much less effort that repeatedly printf debugging.
- cassepipe 2y agoI am not sure I understand your point. Can you be more explicit ?
- shortrounddev2 2y agoMany people believe that a debugger won't work in their specific scenario, but often they are wrong; debugger can connect across network boundaries or into other processes that weren't launched by the IDE
- fisf 2y agoPeople who think that case X cannot be debugged without printf often don't know the features of their debugger. I.e. look at several of the comments which seem to miss that you can: - Remote debug. - Use conditional breakpoints. - Use breakpoints to trigger commands, e.g. log values, enable other breakpoints, etc. instead of stopping. execution. - Debug multi-threaded code. - Disassemble a fragment.
- gregthelaw 2y agoI have a bunch of (36 if you're counting :) short videos and blog posts introducing the advanced features of GDB: https://undo.io/resources/gdb-watchpoint/ https://undo.io/resources/gdb-watchpoint/
- gregthelaw 2y agoJust yesterday I gave a talk at MeetingC++ in Berlin on debugging multithreaded code. It's amazing how few developers know anything beyond the very basic of their debugger. If all you know is print, break, continue, next and then you dismiss the debugger as "not very useful" then you've not made a judgement based on information but on initial reaction.
- mpweiher 2y agoInteresting. My experience is the opposite: I see developers waste hours stepping through their code a line at a time when a few judiciously placed logs (printfs() are fine, but we can do better) would have told them exactly what they needed in a jiffy. If you have a fairly shallow bug, that is a single point in your code that always behaves incorrectly, then I find debuggers reasonably effective. But most of the bugs that I see aren't that shallow, with code misbehaving when the context is just so and perfectly fine otherwise. In those cases, I need to see lots of different invocations and their context. The debugger is like trying to drink the information ocean I need through a straw. A mostly plugged straw. I wonder what makes our experiences so different? Do you unit test a lot? Particularly with TDD? I am guessing that this practice means I just don't get to see a lot of the bugs that a debugger would help me with. (And it doesn't mean I never fire up the debugger. But it is fairly rare).
- setopt 2y agoI have more or less the same experience like you. Logging is a very resilient and adaptable technique – I can use it on my laptop or on remote HPC clusters, almost regardless of programming language (except maybe Haskell), it works fine on parallelized code, and so on, with very little configuration needed. It’s also important to me that it can be done “async”, since some of my larger codes can only be run on HPC clusters by putting a job in a process queue and waiting. I’ve tried debuggers and see the appeal but I find it less useful than print debugging / logging. I also rely heavily on unit tests when writing new code, so that also reduces the surface that I need to look for bugs based on the log. Moreover, most of my projects have 1-3 programmers and can largely “fit in my head” (<10,000 lines of code), so it’s probably different if you work at a FAANG company or something.
- coliveira 2y agoI think you have a great point here. Debugging tools make you dependent on a particular environment. Printing based debugging can work pretty much everywhere. If you master printf programming you can solve any debugging task.
- cmrdporcupine 2y agoEven in multithreaded code, it's absolutely amazing to be able to pause a running program and look at the list of running threads and the values in scope and see where deadlocks might be sitting. It's immediately obvious you're deadlocked, which is actually kind of tricking to suss out with log-style debugging. Modern debuggers can do so much, being able to lay down conditions to only break when certain values are set, etc. etc. Some can even "rewind" programs. I'd say most people (including myself) are using only 25% of their debugger's capabilities. Aside: One the reasons I despise working with async Rust code is the mess it makes of working with a debugger.
- tomjen3 2y agoRider shows the value of assignments in your code, on the line they are assigned when you are debugging. This has saved me time when I notice that a value I didn't even think about looking into was wrong.
- mark_undoio 2y ago> Sure, it doesn't help much for some scenarios (one I've heard people mention is multithreaded code, where logs are better?), but for most people it's not that far from a superpower. Debuggers can be great for understanding multithreaded code - and you can potentially freeze threads and continue others in order to provoke a particular race condition. However they're potentially quite weak at stepping through a concurrency bug - stopping after each line to understand the sequence of events has a good chance of making your bug go away. I'd say you want Time Travel Debugging if you need to capture and step through a rare event: you get to record the bug happening (without interrupting it) and then step through the recording. On Linux, Undo.io (disclaimer: where I work) and rr (open source) are good at this. On Windows, you have Microsoft's own Time Travel Debug solution: https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/time-travel-debugging-overview https://learn.microsoft.com/en-us/windows-hardware/drivers/d... (nb. there's also GDB's built-in process record technology but I'd recommend against that for any non-trivial software as the overheads are very high)
- 0xfeba 2y agoI've had logging slow down a concurrency issue enough to cause the race condition to never appear when logged, but setting a breakpoint (and stopping all threads) prevailed.
- bobmcnamara 2y agoAt least in embedded, often the tools suck. Some ancient version of NetBeans leaking ram like a sieve until it brings down the machine, or a decade old version of Eclipse that can't pull in a newer CDT, running on a fork of OpenOCD with nothing customized for the CPU architecture running dog slow. Sadly, it can be faster to reserve a GPIO, bitbang a TX-only UART, and get on with it.
- shortrounddev2 2y agoI honestly believe it's a cultural thing. I don't think there's any rational reason to not want to use a debugger, but I've met many people who swear it's useless. I think people in web tend not to use debugger, and a lot of Linux people as well. Everybgame developer I've met and most windows programmers use them
- marssaxman 2y agoI made heavy use of interactive debuggers earlier in my career. After several years working in environments where debuggers were broken, unhelpful, or not available, I completely lost the habit. It was not so much a cultural thing as simple practicality: logging always works. I'd rather maximize my limited brainpower by focusing on the software I'm building and thinking as little as possible about the tools I'm using. It may be somewhat cultural in that influence from functional programming eventually changed the way I think about state and state transitions, leading me to design my code differently, reducing the amount of debugging I have to do and making it easier to do via logging.
- crossroadsguy 2y agoSometimes I have had much better results with adding logs especially if an issue doesn't occur always and I am not so sure about the steps either because breakpoints take a lot of time as well. Also, in some cases (esp. mobile UI) breakpoints might actually break the flow and you might not get a proper flow. But yeah mastering the debugger is indeed a must and a GUI debugger is better than a CLI debugger. It's just that at least for me personally logging is first line of debugging :|
- HumblyTossed 2y agoI use debug logs extensively. I log a LOT. I can put the logs and code next to each other and trace through the code. So much better than a debugger. With the logs, I don't have to worry about timers or concurrency or any of that. I can take my time and read the code and reason about what's going on. Edit: Logging helps me look at what is going on in prod as well. I can trace messages/transactions completely through the path and if there's an issue, I'll see it.
- mbrumlow 2y agoIdk. I feel like the second you need to use a debugger your code and design has become too complicated and needs to be rethought. In general anything you would want to debug should probably be exposed as a unit test and the area of concern should have test cases made that trigger the behavior you are concerned about. The entire process of debugging essentially results in the same process as you would need to do to create unit test. While it is faster it is lost once done, making the entire process one shot.
- deleted 2y ago[deleted]
- dsp_person 2y agoI've been writing C code a lot more like scripting after familiarizing with how easy it is to use gdb compared to jumping through hoops say in vscode to setup a new build target for every new C file I want to mess with. Just write `test_x.c`, `gcc -o test_x test_x.c -g`, and `gdb --args ./test_x --blah --blah` allows for much faster iteration on things. PLUS the gdb commands end up far easier and more powerful to probe things than mess with the GUI most of the time.