beginner1010's blog

By beginner1010, history, 4 years ago, In English

Today, I was seeing tourist's submissions. He uses a very cool way to print the variables for the purpose of debugging. The function debug_out lists all variable names, followed by their values. I found it very interesting and convenient.

However, when you would like to print a long list of variables, it might be hard to match variables and their corresponding values. I made a few changes, and I would like to share the code with you. Please note that you need to define XOX (-D XOX should do the job). Therefore, when you are submitting your code, you do not need to remove or comment out lines including debug. Hope you'll find it useful.

#include <bits/stdc++.h>
using namespace std;
vector<string> vec_splitter(string s) {
	s += ',';
	vector<string> res;
	while(!s.empty()) {
		res.push_back(s.substr(0, s.find(',')));
		s = s.substr(s.find(',') + 1);
	}
	return res;
}
void debug_out(
vector<string> __attribute__ ((unused)) args,
__attribute__ ((unused)) int idx, 
__attribute__ ((unused)) int LINE_NUM) { cerr << endl; } 
template <typename Head, typename... Tail>
void debug_out(vector<string> args, int idx, int LINE_NUM, Head H, Tail... T) {
	if(idx > 0) cerr << ", "; else cerr << "Line(" << LINE_NUM << ") ";
	stringstream ss; ss << H;
	cerr << args[idx] << " = " << ss.str();
	debug_out(args, idx + 1, LINE_NUM, T...);
}
#ifdef XOX
#define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
#else
#define debug(...) 42
#endif
int main() {
	int x = -1, y = 10000;
	double z = 0.2;
	string s = "beginner1010";
	long long b = 1LL << 60;
	
	debug(x, y, z, s, b);
	
	double aux = 1010.0;
	string code = "code";
	
	debug(code + "forces",-aux / 10 * 2.3);
	return 0;
}

Results:

Line(34) x = -1,  y = 10000,  z = 0.2,  s = beginner1010,  b = 1152921504606846976
Line(39) code + "forces" = codeforces, -aux / 10 * 2.3 = -232.3

UPD 1: The code is further improved to handle the case when an operation is applied to variables in debug. The line number is added, and spookywooky's suggestion is applied. Please see the examples. Thank you all for your suggestions.

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

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

Auto comment: topic has been updated by beginner1010 (previous revision, new revision, compare).

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

Not as cool, but I use simple

#define watch(x) cout << (#x) << " is " << (x) << endl

to debug single variables

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

void debug_out(vector<string> __attribute__ ((unused)) args, __attribute__ ((unused)) int idx) { cerr << endl; }

to get rid of the compiler warnings caused by -Wunused-parameter

»
4 years ago, # |
Rev. 3   Vote: I like it 0 Vote: I do not like it
it's better, isn't it?
  • »
    »
    4 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    can u please tell me how to handle this debug();

    • »
      »
      »
      4 years ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it
      1. Compile with flag -DLOCAL
      2. Call debug() with some arguments, it will print argname = argvalue
      • »
        »
        »
        »
        3 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        But how to compile with flag -DLOCAL

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

          these are compiler flags , eg -Wall , -Wshadow etc

          just useg++ -D LOCAL filenmae.cpp

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

            Thanks a lot.I know a different way.But I added -DLOCAL as a new compiler flag.But I can't delete my reply.

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

    I don't like that it can't print vectors or function calls. See my comment for better debugging template

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

Auto comment: topic has been updated by beginner1010 (previous revision, new revision, compare).

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

Can we do some modification in above template so that we can also print STl containers like map, vector, set, multiset (also map<pair<int,pair<int,int>>, int> type things).

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

    pretty sure you will have to use iterators there (so i dont think it will work by modifying these functions little bit)

    maybe use something like this to determine whether its an STL container: https://github.com/cpp-libraries/is_stl_container_type_trait/blob/master/is_stl_container.hpp

    then you have to decide if you have to iterate with pairs (for map/unordered_map) also some containers don't have iterators (like queue/deque/stack)

  • »
    »
    4 years ago, # ^ |
    Rev. 2   Vote: I like it +1 Vote: I do not like it

    I think the best way to do this is to define a custom operator<< for STL containers. The magic sauce here is weeding out std::string, but this is relatively easy if you know C++ template metaprogramming.

    Take a look at this code: 76534814. Notice that I have print(a); in main, and a is defined as std::vector<std::string>. This line prints something like this to stderr:

    [154873296, 386592714, 729641835, 863725149, 975314628, 412968357, 631457982, 598236471, 247189563]

    It works for any typical STL container, for example you can have something weird like std::unordered_map<std::pair<int, int>, std::vector<std::string>> b and printing it is still as easy as print(b);

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

This snippet is not printing anything on the console in my PC....No errors, no warnings although... What should I do??

Please help me out!!

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

    same problem with me...

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

      I got the solution

      Just before the #ifdef statement just write down "#define XOX" (without quotes) Commenting this statement will stop printing debug output .

      That's it....It works fine

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

        or you can simply use

        #ifndef ONLINE_JUDGE

        instead of

        #ifdef XOX

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

Here is a function for print any stl container that has begin() and end():

Spoiler

Example:

vector<int> vec{1,2,3,4,5,6};
cout << vec << endl;
set<int> s{3,4,5,6};
cout << s << endl;
//Output
//[1, 2, 3, 4, 5, 6]
//[3, 4, 5, 6]

Work for map too if you overload operator<< for pair

Spoiler
//
map<int,string> m = {
 {1, "awesome"},
 {2, "c++"}
};
cout << m << endl;
//[{1, awesome}, {2, c++}]
map<pair<int,int>,pair<bool,float>> m2 = {
 {{1, 2}, {true, 3.0}},
 {{3, 4}, {false, 9.f}}
};
cout << m2 << endl;
//[{{1, 2}, {1, 3}}, {{3, 4}, {0, 9}}]


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

    We can get rid of vec_splitter() and debug_out() (they won't work if one ARG of #_VA_ARGS__ contain ',')_
    write less code and faster version by using a macro trick

    Spoiler
»
4 years ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it
#ifdef XOX
#define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
#else
#define debug(...) 42
#endif

Here what is meant by

#define debug(...) 42 ???

Why we defined 42 as debug(...)?

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

    because we dont want to print anything in std err while submitting code.** XOX define at local pc (your pc , we need to define this)**

    int a = 10;
    debug(a);
    

    this will print 10 on std::err , but when you submit on cf XOX is not define so debug(a) replace with 42

    int a = 10;
    42;
    
  • »
    »
    4 years ago, # ^ |
      Vote: I like it +8 Vote: I do not like it

    Because 42 is the answer to Life, Universe, and everything, Duh!

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

Hello,

When I do:

int test[10] = {0};
debug(test);

He sends me back:

test = 0x7fffed0acd20

How can I display all my board on the line instead of its address?

Thank you

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

    you can't print this type of array becz size is unknown when it's passed through any function so always use vector

    code

    you have to compile it with LOCAl argument

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

To support STL containers and line number

code
output

just add -D LOCAL flag

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

    I have put #define LOCAL in the code and run it. What I have got is: [x: 10] [y: 11] [v: [1, 2, 3]] [mp: [(12, 13)]] [~ -->Line: 48] ~~ (~ is replacement for some strange symbol that I could not paste into here) Any idea how to fix it?

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

      It's from the backspace \b. I used it to make format the line number a little bit different. you can just remove them from line 34 and line 26.

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

    How to add -D LOCAL flag?

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

      code.cpp

      #include <bits/stdc++.h>
      using namespace std;
      int main()
      {
          #ifdef LOCAL
          {
              cout << "LOCAL defined.";
          }
          #endif
          return 0;
      }
      

      g++ -DLOCAL code.cpp && a.exe

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

    Kavaliro, Thanks a lot for the great debugging template. Yours is the best debugging template I have come across. What can I do to print the line number in the beginning instead of end of the dbg output ?

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

      Just swap arguments

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

how can I print the debug output to a file? currently it prints to terminal

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

Unfortunately this doesn't work when you debug a function call with more than one argument because the commas trick the vec splitter. Guess I'll go back to my not so cool

#define debug(x) cerr << "Line " << __LINE__ << ": " << #x << " = " << to_string(x) << endl
  • »
    »
    4 years ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    I recommend using this debugging template

    Code

    You can debug function calls, variables, STL containers, almost anything.

    Make sure to add -DLOCAL to your compiler arguments. When you write

    edbg(a, b);
    

    where

    a = 5;
    b = "Codeforces";
    

    It will print

    [a]: [5]
    [b]: [Codeforces]
    

    But for a general debug

    dbg(a, b);
    

    it will print

    [a, b]: [5, Codeforces]
    
    • »
      »
      »
      4 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      This edbg macro is basically the same as the post. It dosen't work properly for something like this:

      *min_element(diff.begin() + 2, diff.end())
      

      because the commas separating the arguments of the function mess up the parsing algorithm. I think Tourist's way (which is essentially the same as your dbg function) is sufficient for me.

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

      Your code is not compile

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

I copy and paste your code but it doesn't print anything.

  • »
    »
    3 years ago, # ^ |
    Rev. 2   Vote: I like it +3 Vote: I do not like it
    #ifdef XOX
    #define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
    #else
    #define debug(...) 42
    #endif
    

    If you add the following line before the aforementioned block, It will work.

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

      I couldn't add XOX as compiler flag

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

        I guess you can replace

        #ifdef XOX
        #define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
        #else
        #define debug(...) 42
        #endif
        

        with this

        #ifndef ONLINE_JUDGE
        #define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
        #else
        #define debug(...) 42
        #endif
        
        • »
          »
          »
          »
          »
          3 years ago, # ^ |
            Vote: I like it +1 Vote: I do not like it

          Wow!Its work.Thanks a lot brother.I don't need to add any compiler flag with this.

»
18 months ago, # |
  Vote: I like it 0 Vote: I do not like it

Don't forget to use passing by reference (avoid unnecessary copying):

...
void debug_out(const vector<string>& args, int idx, int LINE_NUM, const Head& H, const Tail&... T) {
...
  • »
    »
    18 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    The length of args is not usually so large, but also there is no harm to pass the parameters by the references...

    • »
      »
      »
      18 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      It's mostly about H and T variables.

»
18 months ago, # |
Rev. 2   Vote: I like it +10 Vote: I do not like it

One stop to debug template and its usage:

https://cs-mshah.github.io/getting_started_with_cp/#debugging

»
18 months ago, # |
  Vote: I like it +10 Vote: I do not like it

I used something similar myself, except one day I was bored so I decided to add the functionality to print stuff in different colors lol. It's hardly the most useful feature but does help sometimes with large implementations

The output —

(Don't judge my code too hard, it's a big steaming pile of mess but I don't have to look at it so I never bother to fix it lol)

If you choose to use it, I recommend you turn word wrap off

#define GREEN "\033[1;32m"
#define YELLOW "\033[1;33m"
#define ORANGE "\033[1;34m"
#define PURPLE "\033[1;35m"
#define BLUE "\033[1;36m"
#define trace(...) __f(__LINE__,YELLOW,#__VA_ARGS__, __VA_ARGS__)
#define Trace(color,...) __f(__LINE__,color,#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(int line, const char *color, const char* name, Arg1&& arg1){
        cerr << "\033[2;37m(Ln " << line << ")\033[0m " << color << name << ": \033[0;37m" << arg1 << "\033[0m " << endl;
    }
    template <typename Arg1, typename... Args>
    void __f(int line, const char *color, const char* names, Arg1&& arg1, Args&&... args){
        const char* comma = strchr(names + 1, ',');
        cerr << "\033[2;37m(Ln " << line << ")\033[0m " << color;
        cerr.write(names, comma - names) << ": \033[0;37m" << arg1 << "\033[0m " << endl;
        __f(line,color, comma+1, args...);
    }

//IO operators for vectors, pairs, sets, maps and __int128 so I can print just about anything
template <typename T>istream &operator>>(istream &in, vector<T> &v){for (auto &i : v)in >> i;return in;}
template <typename T>ostream &operator<<(ostream &ost, vector<T> v){if(&ost == &cerr){cerr <<"{";int cnt = v.size();for(auto x:v){cerr << x;cnt--;if(cnt) cerr << ", ";}cerr << "}";}else for(auto i:v)ost << i << " ";return ost;}
template <typename T>ostream &operator<<(ostream &ost, set<T> s){if(&ost == &cerr){cerr <<"{";int cnt = s.size();for(auto x:s){cerr << x;cnt--;if(cnt) cerr << ", ";}cerr << "}";}else for(auto i:s)ost << i << " ";return ost;}
template <typename T>ostream &operator<<(ostream &ost, multiset<T> s){if(&ost == &cerr){cerr <<"{";int cnt = s.size();for(auto x:s){cerr << x;cnt--;if(cnt) cerr << ", ";}cerr << "}";}else for(auto i:s)ost << i << " ";return ost;}
template <typename U, typename V>ostream &operator<<(ostream &ost, map<U,V> &m){if(&ost == &cerr){cerr <<"{";int cnt = m.size();for(auto x:m){cerr << x; cnt--;if(cnt) cerr << ", ";}cerr << "}";}else for(auto i:m)ost << i;return ost;}
template <typename U, typename V>istream &operator>>(istream &in, pair<U, V> &p){in>>p.first>>p.second;return in;}
template <typename U, typename V>ostream &operator<<(ostream &ost, pair<U, V> p){if (&ost == &cerr)ost << "{" << p.first << ": " << p.second << "}";else ost << p.first << " " << p.second << " ";return ost;}
ostream &operator<<(ostream &ost, __int128_t x){string output = "";while(x)output += '0'+x%10, x /= 10;reverse(all(output)); ost << output;  return ost;}
istream &operator>>(istream &in, __int128_t &x){x=0;string num;cin >> num;for(char c:num) x *= 10, x += c-'0';return in;}
//Variadic IO
template <typename... T>void read(T &...args){((cin >> args), ...);}
template <typename... T>void print(T... args){((cout << args << " "), ...);cout << endl;}

void solve()
{
    vector<int> v = {1,2,3};
    int a = 2;
    map<int,int> m;
    m[5] = 3;
    m[4] = 2;
    m[1] = 7;
    trace(v,a,m);
    Trace(ORANGE,v,a,m);
}
  • »
    »
    18 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Sweet.. You may let the implementation decide the color based on the type of the variable. One question: are the color codes OS agnostic?

    • »
      »
      »
      18 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      Ohh, that's a good idea, I'll see if I can do that without too many lines of code.
      The codes do work on both windows and Linux but the colors themselves change according to your terminal's theme. For example I use Monokai Pro with some tweaks I made myself, but in Default Dark vscode theme the ORANGE color is printed in blue