I use GCC exclusively, and its type-checking of param types vs format string largely prevents me from spending time in gdb; pre-GCC adoption, the biggest source of segfaults in my world was printf type mismatches.
Addendum:
I'm sure it violates every coding convention ever created, but, in almost all cases, once I add a debug printf to my source code, for example,
ED && DBG( "%s", foostr ); // ED is usually a function-scoped enum normally ==0
I leave it there forever. This allows all DBG's to be eternally subject to GCC printf param type build time checking going forward (preventing the debug print code from rotting (as it absolutely would if commented out), at minor maintenance cost (typically only when I switch to a new GCC release)) while not imposing any runtime cost (unless I flip ED to 1 and rebuild to enable function-specific detailed logging).As far as this practice injecting large amounts of comprehension-thwarting noise into my source code: all such `ED && DBG(...);` code sequences are positioned in their own column far to the right of the non-DBG code (needless to say, I don't subject myself to 80-column coding-convention limits; more like 160-column). That this results in multiple statements per line (another typical taboo) is a don't care, since I'm never using a debugger to single-step thru code, and in any case, by convention my DBG() calls never modify program state.
It works great for me, but probably not for anyone else.