Hello Codeforces,
It is sometimes required in competitive programming contests, specially in long-time challenges when there is enough time to trace the program execution behavior at run-time before submitting it to the automatic judge, to track the passed arguments and return value of some C++ function(s). This blog presents a simple C++ tracer class for such purpose.
The following is the class declaration and implementation.
If the macro TRACE
is defined before this tracer code, the following trace operations are enabled using Variadic Macros and Variadic Function Templates.
tr_begin(...)
macro call increments the trace depth, and then prints the passed arguments.tr(...)
macro call prints the passed arguments without updating the trace depth.tr_end(...)
macro call prints the passed arguments, decrements the trace depth, and returns the first argument. This call can be used as the return value of the traced function.
Each traced function should have a tr_begin(...)
macro call at the beginning of the function block, a tr_end(...)
macro call at the end of the function block, and zero or more tr(...)
macro call(s) inside the function block.
If the TRACE
macro is undefined before the tracer code, the aforementioned trace operations are disabled.
The following is an example program to test the functionality of the tracer by tracking the execution of the recursive algorithm for computing the factorial function $$$n!$$$.
The following is the standard output printed results of the example program when the TRACE macro is defined.
Your constructive comments and feedback are evermore welcome.
Update
The following are interesting related blogs, shared thankfully by other Codeforces members.
- darkkcyan, My CP debugging template, shared by jalsol.
- rachitiitr, C++ Trick — Easy Debugging / Logging, shared by Manan_shah.
The trace macros
trace_call(...)
andtrace_ret(...)
were renamed totr_begin(...)
andtr_end(...)
, respectively, and a third macrotr(...)
was added. The value of the built-in macro__LINE__
was also passed to each tracer object public member function call so as to identify the location of the trace point inside the traced function.The macro
db()
by darkkcyan was adopted. If the macroTRACE
is defined, thendb(arg)
producesstring(arg)+" = "+tracer.stringify(arg)
. Any variadic argument of the macro callstr_begin(...)
,tr(...)
, ortr_end(ans,...)
can be passed as eitherarg
ordb(arg)
The following is the GitHub archive of the tracer code.
I suppose you can just print the arguments passed in and return value, so this only keeps track of recursion depth?
Yes, the following code should perform the same operation done by the tracer object in the factorial function example if the trace depth is ignored.
The main advantages of the tracer class are that the conditional compilation commands are implicitly written using the
trace_call
andtrace_ret
macros, and that more compact code in required to perform the same operation.Thank to CodingKnight for blog,
For those who are having problem with new line (in my case Sublime Text 3) :
Replace : header(++trace_depth,fun,args...), pause("called"); }
With this : header(++trace_depth,fun,args...), pause("called\n"); }
Replace : header(trace_depth--,fun,args...), pause("return value = ",ans);
With this : header(trace_depth--, fun, args...), pause("return value = ", ans), pause("\n");
1.Also no need to add header files just use your bits header in place of those.
(You can also delete this line)
2.May be by seeing his example it looks little complex, let me make easier for you :
and write your code as you wrote your before.it will perfect and when u have to debug just comment out #LOCAL
For people who don't like lengthy codes and using sublime text 3 :
Code Folding :
Select the code and press:
Ctrl + Shift + [ to fold
Ctrl + Shift + ] to unfold
(It's a GIF , please click on image to view how it works :))
Thanks for the constructive feedback. Yes, it is surely possible to add new-line character and to use two pause calls inside the
tracer_t::ret
function. I assumed that the tracer code is placed at the beginning of the program code. But it is surely possible to remove the header files and all thestd::
prefixes from the tracer code if it is placed after the convenient competitive programming first couple of C++ lines:This from darkkcyan can do somewhat the same thing, but much simpler to implement, so it's superior to me.
Thanks for sharing the link to that interesting blog. The
db()
macro is surely more powerful than the macros declared and implemented in this blog, as the former uses the preprocessor operator#
to add the code text to the trace information.Here is what I use and found to be the simplest: link to my comment
Thanks for sharing the link to that interesting blog.