I\'m using a lot of printf for tracing/logging purposes in my code, I\'ve found
ID: 653049 • Letter: I
Question
I'm using a lot of printf for tracing/logging purposes in my code, I've found that it's a source of programming error. I always found the insertion operator (<<) to be somewhat of a odd thing but I'm beginning to think that by using it instead I could avoid some of these bugs.
Anyone ever had a similar revelation or I'm just grasping at straws here?
Some take away points
My current line of thinking is that type-safety outweighs any benefit of using printf. The real problem is the format string and the use of non type-safe variadic functions.
Maybe I won't be using << and the stl output stream variants but I will certainly look into using a type-safe mechanism which is very similar.
A lot of the tracing/logging is conditional but I'd like to always run the code to not miss bugs in tests just because it's a rarely taken branch.
Explanation / Answer
printf, particularly in cases where you might care about performance (such as sprintf and fprintf) is a really strange hack. It constantly amazes me that people who pound on C++ due to miniscule performance overhead related to virtual functions will then go on to defend C's io.
Yes, in order to figure out the format of our output, something that we can know 100% at compile time, let's parse a fricken format string at runtime inside a massively weird jump table using inscrutable format codes!
Of course these format codes couldn't be made to match the types they represent, that would be too easy... and you're reminded every time you lookup whether it's %llg or %lg that this (strongly typed) language makes you figure out types manually to print/scan something, AND was designed for pre-32bit processors.
I'll admit that C++'s handling of format width and precision is bulky and could use some syntactic sugar, but that doesn't mean you have to defend the bizarre hack that is C's main io system. The absolute basics are pretty easy in either language (although you should probably be using something like a custom error function/error stream for debug code anyways), the moderate cases are regex-like in C (easy to write, hard to parse/debug), and the complex cases impossible in C.
(If you use the standard containers at all, write yourself some quick templated operator<< overloads that allow you to do things like std::cout << my_list << " "; for debug, where my_list is of type list<vector<pair<int,string> > >.)