Sadly printf debugging still captures something about the investigation process of humans, something debuggers don't handle well at first, until you're used to them and know how to map. It's blurry in my mind but you want to handle sets of breakpoints and custom structure IO/formatting for a debugging session, and debuggers don't offer a way to smooth this out (I'm no expert though, grain of salt required) so printf(...) is still a large reflex.
printfs are usually good. However when you deal with complex realtime multithreaded processes, sometimes high priority thread just pre-empts the printf, so you need to use somekind of flush statements ...this delays overall operations. In such cases debuggers are good 'to some extent'. I still haven't found the best way to debug hard realtime multithreaded applications
Those are exactly the places I find myself relying on printfs. In real-time, multithreaded code, you can't block on a thread and inspect things for a couple minutes and expect it to resume working afterwards.