rachitiitr's blog

By rachitiitr, 3 years ago, In English

Hi Community,

It's been a while I wrote a blog post here.
You can follow more such tricks on —

How debug macros work?

Straight to the point, I have often used the debug macro which stringifies the variable names and their values.

#define deb(x) cout << #x << " " << x 
int ten = 10;
deb(ten); // prints "ten = 10"

This is often useful in debugging.

The Problem with this macro — its not scalable

However, when you have multiple variables to log, you end up with more deb2 and deb3 macros.

#define deb(x) cout << #x << " " << x 
#define deb2(x) cout << #x << " " << x << " "  << #y << " " << y 
#define deb3(x, y, z) cout << #x << " " << x << " "  << #y << " " << y << " "  << #z << " " << z 

This is not scalable.

Solution using a powerful macro

Here is the solution using variadic macros and fold expressions,

#define deb(...) logger(#__VA_ARGS__, __VA_ARGS__)
template<typename ...Args>
void logger(string vars, Args&&... values) {
    cout << vars << " = ";
    string delim = "";
    (..., (cout << delim << values, delim = ", "));
}

int xx = 3, yy = 10, xxyy = 103;
deb(xx); // prints "xx = 3"
deb(xx, yy, xxyy); // prints "xx, yy, xxyy = 3, 10, 103"

Hope this helps, this is going to my template for sure

  • Vote: I like it
  • +139
  • Vote: I do not like it

| Write comment?
»
3 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Bro, you can overload macro in c++ like this: __#define GET_MACRO6(_1,_2,_3,_4,_5,_6,NAME,...) NAME__ __define deb_1(a)__ __define deb_2(a,b)__ __define deb_3(a,b,c)__ __define deb_4(a,b,c,d)__ __define deb_5(a,b,c,d,e)__ __define deb_6(a,b,c,d,e,f)__ __define deb(...) GET_MACRO6(__VA_ARGS__,deb_6,deb_5,deb_4,deb_3,deb_2,deb_1)(__VA_ARGS__)__

my full debug code: https://github.com/Wgmlgz/Random-code/blob/main/Cp/template.cpp

  • »
    »
    3 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    The issue with this is readability. Parameter packs and variadic templates seem like the future and easy to read (when you know how they work).

»
3 years ago, # |
  Vote: I like it +11 Vote: I do not like it

I use something like this

#define gg(...) [](const auto&...x){ char c='='; cerr<<#__VA_ARGS__<<" "; ((cerr<<exchange(c,',')<<" "<<x),...); cerr<<endl; }(__VA_ARGS__);

usage the same

»
3 years ago, # |
  Vote: I like it +8 Vote: I do not like it

I simply straight up copied tourist's debugging template

»
3 years ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

Thanks but you still have to comment it out before submitting. Maybe use cerr ?

  • »
    »
    3 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    what is the benefit to use cerr?

    • »
      »
      »
      3 years ago, # ^ |
        Vote: I like it +4 Vote: I do not like it

      You dont have to comment your debug line during submitting for judging, you can leave there as it is. cerr prints its contents to a separate error log.

»
3 years ago, # |
Rev. 3   Vote: I like it +18 Vote: I do not like it

I did some research and searched for very good debugging techniques and templates. So this is what I felt is the best method for debugging, and this works for several stl containers including maps and even policy based data structures.

Here is the template:

myprettyprint.hpp

Now, you might be feel that this would make my default template a lot more scary and confusing. So a solution to that is to use the #ifndef ONLINE_JUDGE preprocessor directive, and include the debug template as a .hpp file.

main template

Results:

output

note: the myprettyprint.hpp should be placed in a directory so that it is in the search path when compiling.
in ubuntu, I placed it here: /usr/include/c++/9/myprettyprint.hpp. I hope this helps!

original source: link1, link2

  • »
    »
    3 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Thanks for this idea! I just want to know that where should I place this hpp file? Inside my compiler's folder (where "bits/stdc++.h" is placed?)

    • »
      »
      »
      3 years ago, # ^ |
        Vote: I like it +1 Vote: I do not like it

      "bits/stdc++.h" if placed under ubuntu (/usr/include/x86_64-linux-gnu/c++/9/bits) and for arch linux (/usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits).

      You should put "headerfile.hpp" in the above directory and use it like this

      code
      • »
        »
        »
        »
        3 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Got it.

        One doubt though that #define dbg(...) what does this do? Do I need to have some other dbg macro defined above for it to work or is it self sufficient?

        • »
          »
          »
          »
          »
          3 years ago, # ^ |
          Rev. 2   Vote: I like it 0 Vote: I do not like it

          One doubt though that #define dbg(...) what does this do
          This will make every dbg(..) statemets an EMPTY line. So, you dont have to comment out every dbg(..) statement in your code before submitting it.✌️
          And it is self sufficient.

»
3 years ago, # |
Rev. 2   Vote: I like it +3 Vote: I do not like it

I simply use one existing pretty print header file

Update: put this in your stdc++.h

#ifdef LOCAL
#include<pprint.hpp>
pprint::PrettyPrinter _printer(std::cerr);
#define de(...) _printer.compact(true).print('[', #__VA_ARGS__,"] =", __VA_ARGS__)
#define de2(...) _printer.compact(false).print('[', #__VA_ARGS__,"] =", __VA_ARGS__)
#endif

and put this in your source code:

#ifndef LOCAL // https://github.com/p-ranav/pprint
#define de(...)
#define de2(...)
#endif
  • »
    »
    3 years ago, # ^ |
    Rev. 2   Vote: I like it +1 Vote: I do not like it

    I tried to compile and it threw several errors. Am I missing something?
    [edit] fixed : I was not using c++17

»
3 years ago, # |
  Vote: I like it 0 Vote: I do not like it

use fmtlib and wait for C++20

#include "fmt/core.h"

fmt::print("x={} y={} z={}\n", x, y, z);
»
3 years ago, # |
  Vote: I like it 0 Vote: I do not like it

This is what I use, It looks pretty lengthy and ugly but works like a charm for me.

Debug Template
»
3 years ago, # |
Rev. 3   Vote: I like it +8 Vote: I do not like it

I think most of the solutions for debugging here are quite non-generic in nature. I used to have such a debug template too (albeit with variadic macros and lots of overloads for printing STL containers). Then I came across Narut's awesome template for debugging that uses SFINAE in a pretty clever way, and I tinkered with it slightly to make it work with my old pretty printing template, to get the following result:

Debugging template

Note: This would work only with C++17 and later (because of std::apply and if constexpr among others).

Some advantages:

  1. Doing debug(a, b, c) (or any number of parameters) pretty prints variables a, b, c of any sane type defined in the C++ standard or STL (sane as in something that makes sense to be printed). For instance, if it is a pair or an arbitrary tuple of printable types, or a container of printable types, it can be printed using this template, and is hence a printable type. No need to define printing functions for literally every single type. You can print stuff like vector<pair<string, vector<tuple<int, char>>>> with this template too.

  2. It prints the line numbers as well, and takes care of printing containers in separate lines. In terms of formatting, it gives you a nice coloured output too.

For those curious, here's the explanation of how it works.

Explanation

And, of course, it's always better to have this all neatly packed into a local header like debug.hpp which helps in keeping your submission clean!

»
3 years ago, # |
  Vote: I like it +3 Vote: I do not like it

May you suggest other resources for further reading regarding variadic macros and fold expressions. Thanks !

»
3 years ago, # |
  Vote: I like it +5 Vote: I do not like it

Great article! I'd like to suggest the following:

  • print all variables to stderr to have only solution output in stdout (useful if you're using additional tooling to check your code)
  • run this code only in debug mode (e.g., you can log some expensive function calls)

I mostly covered these topics in my article, feel free to check it out!

»
3 years ago, # |
  Vote: I like it +3 Vote: I do not like it

I am getting the below warning and my code isn't running.

warning: fold-expressions only available with '-std=c++17' or '-std=gnu++17'
   54 | (..., (cout << delim << values, delim = ", "));

The standard for the CPP set is already c++17 in my vs code.

Please help me in setting this debug code as my template.

  • »
    »
    3 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Getting same error, have you found a solution yet?

»
14 months ago, # |
  Vote: I like it +3 Vote: I do not like it
#ifdef LOCAL
#include "/Library/debug/debug.h"
#define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define debug(x...)
#endif

I'm putting all my ugly debugging code inside "debug.h" file and include it only if I'm compiling the file locally, and also calling the debug function from an online judge will print nothing.