A C/C++ feature that helped me to log better
I read an article some time ago where it claims that you take at least 10 years to learn C/C++ entirely. I don’t remember if was Bjarne Stroustrup or someone else that said that but I completely agree!
I program professionally for about 8 years and most of my career was developing in C/C++, still I don’t consider I know everything about this terrific language. One prove is that I found an interesting feature available regarding #define macros!
Let’s LOG
One important thing of every program is log. It’s used to trace program’s flow or even debug on some cases where you cannot use GDB/DBX.
That being said, one important thing to put on your logs is the file name and line number where the it occurs. On my early days I though to have found a smart way to do it!
Well, I created a log function that here I’ll simplify it a little:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include #include void log(const char* fileName, int line, const char* msg, ...) { va_list args; va_start(args, msg); fprintf(stdout, "%s, %d:", fileName, line); vfprintf(stdout, msg, args); fprintf(stdout, "\n"); va_end(args); } |
Now I can use this just like a simple printf:
10 11 | int var = 50; log("MyFile.cpp", 11, "Hello var: %d", var); |
The problem with this, show up when I add couple lines before it:
10 11 12 13 | // trace var value int var = 50; log("MyFile.cpp", 11, "Hello var: %d", var); |
This time the output of this will still be:
MyFile.cpp, 11: Hello var: 50
The problem is this line is wrong now! And imagine fixing all the logs of a 1000 LOC file if you just add an include?
How to solve this?
Standard Predefined Macros
If you check The GNU C Preprocessor page that talks about Standard Predefined Macros you’ll find two interesting macros that solve our problem:
__FILE__– This macro expands to the name of the current input file, in the form of a C string constant.__LINE__– This macro expands to the current input line number, in the form of a decimal integer constant.
Well, now if we use our log function with this macros we’re safe:
10 11 12 13 | // trace var value int var = 50; log(__FILE__, __LINE__, "Hello var: %d", var); |
This time the output of this will be:
MyFile.cpp, 13: Hello var: 50
Cool right?
Yes but if you start working with a bunch of people you’ll realize that use this standard macros might confuse some folks and others tend to use plain printf just because they don’t know how to use it.
Now, how to solve THIS problem?
#define Macros to save us
It turns out there is a feature on standard C called Variadic Macros that I didn’t know before this week that simply solve this issue and make log functions elegant and efficient.
I’ll point you again to the The GNU C Preprocessor on the Variadic Macros page so you can read the details, but in a glimpse here is its syntax:
#define MACRO_NAME(arg, ...) somefunc(arg, __VA_ARGS__)One thing to notice though is that with this syntax you must pass at least one argument as variable arguments due the comma on your macro definition. But don’t look to this post with this face! There is a second syntax of Variadic Macros that will calm you down:
#define MACRO_NAME(arg, ...) somefunc(arg, ##__VA_ARGS__)With those double pounds before the __VA_ARGS__ keyword, the C preprocessor will know if you don’t add variable arguments and will take the comma out.
Now, how this will help us on our log function?
Easy, we create this macro:
#define LOG(msg, ...) log(__FILE__, __LINE__, msg, ##__VA_ARGS__)Now our code snippet can be re-writen to use this new macro:
10 11 12 13 | // trace var value int var = 50; LOG("Hello var: %d", var); |
As I said: cleaner and more elegant
!
One Response to “A C/C++ feature that helped me to log better”
Leave a Reply

Hey Thiago, how are you?
Another useful thing for those macros: http://www.pontov.com.br/site/index.php/cpp/46-conceitos-basicos/90-detectando-memory-leaks