andrewtam's blog

By andrewtam, history, 3 years ago, In English

Context: On a recent contest I got Java'ed so I decided that I would permanently switch to C++. That being said, I found that generally C++ debuggers were less effective than the one I'm currently using for Java (this is my personal opinion, feel free to disagree). Fast forward to today, I was complaining on Discord that I couldn't get my debugger to work properly and in response, my friend told me that debuggers are "stupid" and that "nobody uses a debugger." This started a mini-debate about debuggers and who uses them which brings me back to my original question: do you use a debugger? Please let me know in the comments.

Have a great day!

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

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

I don't use a debugger for simple code, but when the code gets complex and values in multiple data structures change, I find it great to use a debugger to understand at each major step whether everything's going correctly.

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

Personally, printing stuff has always been sufficient for spotting bugs.

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

I personally don't use a debugger, but passing -fsanitize=address -fsanitize=undefined while compiling has caught a lot of undefined behavior and logic errors.

Although sometimes the errors still tend to take a while to debug, so maybe I should be using a debugger...

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

I use -Wshadow -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -fsanitize=address -fsanitize=undefined to avoid some common mistakes I make.

For debugging besides this, I just print stuff like everyone else

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

    Hi can you explain what does that line do ?
    is that useful in debugging runtime errors ?

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

      This explains them nicely.

      And yea this helps in runtime errors but you have to use STL containers for it.

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

what do you mean you got java'ed

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

    Getting Java'ed is when you write a correct solution that passes in C++ or any fast language but fails in java because java is slower.

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

    Look at their submissions:

    this in Java (in-contest, TLE)
    this in C++ (after the contest, AC)

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

I always use the debugger.

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

I don't use a debugger.

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

    Probably because you are too smart and have never made a mistake in your code before.

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

      No, because it's slow, output debug works better for me.

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

I use debugger very rarely. Most error can be caught with printing values of variables.

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

A funny debugging trick if you don't like to use a debugger like me:

When having a runtime error, I used to do a binary seach to find the line with the error, by putting cout << "Ending..." << endl; exit(0); in the middle of the code, if my code reached it I search the second half, otherwise I search the first half and I repeat until I find the line.

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

    Even better: It's faster to copy and paste that line (without the exit(0);) onto several lines where you think the runtime error could occur. Basically an N-ary search where you put N-1 copies of that line.

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

      binary search applied! assert(0) after including the cassert library also works for this purpose.

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

    Do you not get a nice stack backtrace pointing to the exact source code line when debugging code locally on your computer?

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

      I'm pretty sure you can only get that with compiler arguments that enable debugging things (see comments above).

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

      Is there a way to do this when the code segfaults? I had tried to find a solution that doesn't involve using GDB, but failed. I know there are a couple of ways using some libraries but I prefer not to use them in a competitive programming context.

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

        Is there a way to do this when the code segfaults?

        Compiling a program with "-g" option adds debugging information to it. This extra debugging information does not make the program slower. It's basically just an extra appended data structure, which allows to map address ranges in the executable to the lines in the source code. Plus some information about how to decipher stack at any point in order to be able to extract return addresses and the values of local variables.

        Now what to do if the program segfaults? In Linux it's possible to enable creation of core dumps via "ulimit -c unlimited" command. A core dump file is a snapshot of memory at the time of the crash, which can be later inspected by GDB to see what was going on. Here is an example:

        Spoiler

        GDB was executed non-interactively in batch mode to just decipher and print a backtrace. It didn't execute the program and didn't require any user input. I'm not a big fan of interactive single step debugging myself.

        I had tried to find a solution that doesn't involve using GDB, but failed.

        As the others already mentioned, it's also possible to use "-fsanitize=address -fsanitize=undefined" options in the GCC command line. And we get a backtrace for free without any extra GDB invocation gymnastics:

        Spoiler

        These options slow down the program because a lot of extra safety checks are added in the generated code. But this is a small price if it helps to find a bug.

        GDB, sanitizer options and tools like valgrind help to deal with segfaults without having to resort to bisecting via debugging prints. I believe that debugging prints are a much slower method in this particular situation.

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

          Thanks for the nice and detailed explanation! I follow a pretty similar debugging pattern too. I have "-fsanitize=address -fsanitize=undefined" in my debug configuration as well, but it comes into play very rarely (and it indeed shows the given backtrace). I might have been ambiguous about the previous question, and I apologize for not having clarified my issue earlier.

          I believe that the reason it is not super useful for me (but useful at appropriate times because getting such errors is usually a signature of a much bigger problem) is because mostly the errors I am concerned with are out of bounds errors, and I like using vectors rather than arrays, so when I compile my code with _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC, it throws an exception rather than give me a nice backtrace. For instance, an out of bounds error gives me something like:

          Spoiler

          For this exception, I much rather prefer having a backtrace than this isolated piece of information. I prefer using _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC since they also add in checks for preconditions on algorithms, which is quite handy (even if my binary search might become $$$O(n)$$$, which I don't really care about while debugging). To get the backtrace, I just use GDB to look at where the exception has been thrown. This isn't too big of an inconvenience for me, but it would be pretty instructive to get around this.

          I think my original question should rather have been this:

          Is there a way to print a backtrace for exceptions thrown by the code?

          Please let me know if this can be done cleanly (I think there's no obvious solution clean solution to this, but just in case). Thanks!

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

            Compiling with _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC results in a call of "abort" function in the end (at least on my system). It is possible to set a breakpoint on "abort" function in GDB, run program and then ask for a backtrace when the breakpoint is reached. Or alternatively, maybe try something like this:

            Source code
            Output

            That's a lot of noise on the console, but at least the offending line "testvect.cpp:10" is present in the backtrace.

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

no need for debuggers when you can just write cout << "haha penis\n"; :)

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

No

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

I sometimes use the debugger. I believe it is quite useful in case you have a runtime error or some random wa on a big sample test. You however need to take care as debugging with the debugger takes a lot of time and you can easily spend half of the contest on it.

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

I use a hybrid of print debugging (for unexpected outputs) and GDB (for segfaults or other issues where the program dies, and I need a backtrace). This tends to be pretty fast for me.

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

This is what I use: cf comment.
These are my debug flags:
g++ -std=c++1z -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -g -fsanitize=undefined

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

Yes (but on a case-by-case basis, it's not hard to decide whether print statemets or gdb is more efficient).

One thing that is really great about gdb: you can instantly tell exactly where your code got a segfault. No need for some binary searching with print statements. In a sense, it also works for figuring out where your code gets stuck in an infinite loop.

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

cout is your best debugger

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

i use CLion and it's easy to debug here.

I also switched from java to c++ and here are two defines to debug your code:

First define
2nd define
»
3 years ago, # |
  Vote: I like it 0 Vote: I do not like it

No.

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

I started it using a few weeks ago and dropped it about a week ago, because it makes the code slow and sometimes leads to TLE :(

And so I realised "cout" orz ;)

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

I use a debugger only to obtain stack traces after program crashes.

And yes, -D_GLIBCXX_DEBUG (as mentioned above many times) is a very useful compiler option.

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

When you have a bug, its better to check the code once before starting to print out everything; but if you didn't find the bug, using a debugger can save lots of time.