Search

1.11 — Debugging your program (stepping and breakpoints)

Syntax and semantic errors

Programming can be difficult, and there are a lot of ways to make mistakes. Errors generally fall into one of two categories: syntax errors, and semantic errors (logic errors).

A syntax error occurs when you write a statement that is not valid according to the grammar of the C++ language. This includes errors such as missing semicolons, undeclared variables, mismatched parentheses or braces, and unterminated strings. For example, the following program contains quite a few syntax errors:

Fortunately, the compiler will generally catch syntax errors and generate warnings or errors, so you easily identify and fix the problem. Then it’s just a matter of compiling again until you get rid of all the errors.

Once your program is compiling correctly, getting it to actually produce the result(s) you want can be tricky. A semantic error occurs when a statement is syntactically valid, but does not do what the programmer intended.

Sometimes these will cause your program to crash, such as in the case of a divide by zero:

Sometimes these will just produce the wrong value:

or

Unfortunately, the compiler will not be able to catch these types of problems, because the compiler only knows what you wrote, not what you intended.

In the above example, the errors are fairly easy to spot. But in most non-trivial programs, many semantic errors will not be easy to find by eyeballing the code.

Fortunately, that’s where a debugger can really come in handy.

The debugger

A debugger is a computer program that allows the programmer to control how a program executes and watch what happens as it runs. For example, the programmer can use a debugger to execute a program line by line, examining the value of variables along the way. By comparing the actual value of variables to what is expected, or watching the path of execution through the code, the debugger can help immensely in tracking down semantic errors.

Early debuggers, such as gdb, had command-line interfaces, where the programmer had to type arcane commands to make them work. Later debuggers (such as Borland’s turbo debugger) came with their own “graphical” front ends to make working with them easier. Almost all modern IDEs available these days have integrated debuggers -- that is, the debugger is built-in to the editor, so you can debug using the same environment that you use to write your code (rather than having to switch programs).

Nearly all modern debuggers contain the same standard set of basic features -- however, there is little consistency in terms of how the menus to access these features are arranged, and even less consistency in the keyboard shortcuts. Although our examples will be from Microsoft Visual Studio 2005 Express, you should have little trouble figuring out how to access each feature we discuss no matter which development environment you are using.

Before proceeding: Make sure your program is set to use the debug build configuration.

Stepping

Stepping is a debugger feature that lets you execute (step through) your code line by line. This allows you to examine each line of code in isolation to determine whether it is behaving as intended.

There are actually 3 different stepping commands: step into, step over, and step out. We will cover each one in turn.

Step into

The step into command executes the next line of code. If this line is a function call, step into enters the function and returns control at the top of the function.

Let’s take a look at a very simple program:

As you know, when running a program, execution begins with a call to main(). Because we want to debug inside of main(), let’s begin by using the “Step into” command.

In Visual Studio 2005 Express, go to the debug menu and choose “Step Into”, or press F11.
If you are using a different IDE, find the “Step Into” command in the menus and select it.

When you do this, two things should happen. First, because our application is a console program, a console output window should open. It will be empty because we haven’t output anything yet. Second, you should see some kind of marker appear to the left of the opening brace of main. In Visual Studio 2005 Express, this marker is a yellow arrow. If you are using a different IDE, you should see something that serves the same purpose.

This arrow marker indicates that the line being pointed to will be executed next. In this case, the debugger is telling us that the next line that will be executed is the opening brace of main(). Choose “Step into” again to execute the opening brace, and the arrow will move to the next line.

This means the next line that will be executed is the call to printValue(). Choose “Step into” again. Because printValue() was a function call, we “Step into” the function, and the arrow should be at the top of the printValue() code.

Choose “Step into” to execute the opening brace of printValue().

At this point, the arrow should be pointing to std::cout << nValue;.

Choose “Step over” this time (this will execute this statement without stepping into the code for operator<<). Because the cout statement has now been executed, you should see that the value 5 appears in the output window.

Choose “Step into” again to execute the closing brace of printValue(). At this point, printValue() has finished executing and control is returned to main().

You will note that the arrow is again pointing to printValue()!

While you might think that the debugger intends to call printValue() again, in actuality the debugger is just letting you know that it is returning from the function call.

Choose “Step into” twice more. At this point, we have executed all the lines in our program, so we are done. Some debuggers will terminate the debugging session automatically at this point. Visual Studio does not, so if you’re using Visual Studio, choose “Stop Debugging” from the debug menu. This will terminate your debugging session.

Note that “Stop Debugging” can be used at any point in the debugging process to end the debugging session.

Step over

Like “Step into”, The Step over command executes the next line of code. If this line is a function call, “Step over” executes all the code in the function and returns control to you after the function has been executed.

Note for Code::Blocks users: In Code::Blocks, “Step over” is called “Next Line”.

Let’s take a look at an example of this using the same program as above:

“Step into” the program until the next statement to be executed is the call to printValue().

Instead of stepping into printValue(), choose “Step over” instead. The debugger will execute the function (which prints the value 5 in the output window) and then return control to you on the next line (return 0;).

Step over provides a convenient way to skip functions when you are sure they already work or do not need to be debugged.

Step out

Unlike the other two stepping commands, “Step out” does not just execute the next line of code. Instead, it executes all remaining code in the function you are currently in, and returns control to you when the function has finished executing.

Let’s take a look at an example of this using the same program as above:

“Step into” the program until you are inside printValue().

Then choose “Step out”. You will notice the value 5 appears in the output window, and the debugger returns control to you after the function has terminated.

Run to cursor

While stepping is useful for examining each individual line of your code in isolation, in a large program, it can take a long time to step through your code just to get to the point where you want to examine in more detail.

Fortunately, modern debuggers provide a few more tools to help us efficiently debug our programs.

The first useful command is commonly called Run to cursor. This command executes the program like normal until it gets to the line of code selected by your cursor. Then it returns control to you so you can debug starting at that point. Let’s try it using the same program we’ve been using:

Simply put your cursor on the std::cout << nValue; line inside of printValue(), then right click and choose “Run to cursor”.

You will notice the arrow indicating the line that will be executed next moves to the line you just selected. Your program executed up to this point and is now waiting for your further debugging commands.

Run

Once you’re in the middle of debugging a program, you can tell the debugger to run until it hits the end of the program (or the next breakpoint, which we’ll discuss in a second). In Visual Studio 2005 Express, this command is called “Continue”. In other debuggers, it may be called “Run” or “Go”.

If you have been following along with the examples, you should now be inside the printValue() function. Choose the run command, and your program will finish executing and then terminate.

Breakpoints

The last topic we are going to talk about in this section is breakpoints. A breakpoint is a special marker that tells the debugger to stop execution of the program at the breakpoint when running in debug mode.

To set a breakpoint in Visual Studio 2005 Express, go to the Debug menu and choose “Toggle Breakpoint” (you can also right click, choose Breakpoint -> Insert Breakpoint). You will see a new type of icon appear:

Go ahead and set a breakpoint on the line std::cout << nValue;.

Now, choose “Step into” to start a debugging session, and then “Continue” to have the debugger run your code, and let’s see the breakpoint in action. You will notice that instead of running all the way to the end of the program, the debugger stopped at the breakpoint!

Breakpoints are extremely useful if you want to examine a particular section of code. Simply set a breakpoint at the top of that section of code, tell the debugger to run, and the debugger will automatically stop every time it hits that breakpoint. Then you can use the stepping commands from there to watch your program run line by line.

One last note: Up until now, we’ve been using “step into” to start debugging sessions. However, it is possible to tell the debugger to just start running to the end of the program immediately. In Visual Studio 2005 Express, this is done by picking “Start debugging” from the Debug menu. Other debuggers will have similar commands. This, when used in conjunction with breakpoints, can reduce the number of commands you need to use to get to the spot you want to debug in more detail using the stepping commands.

Conclusion

Congratulations, you now know all of the major ways to make the debugger move through your code. However, this is only half of what makes debuggers useful. The next lesson will talk about how to examine the value of variables while we are debugging, as well as a couple of additional windows of information we can make use of to help debug our code.

1.11a -- Debugging your program (watching variables and the call stack)
Index
1.10b -- How to design your first programs

65 comments to 1.11 — Debugging your program (stepping and breakpoints)

  • Jason

    Typos

    First, an (a) console output window should open.

    A breakpoint is a special marker that tells the debugger to step (stop) execution of the program at the breakpoint when running in debug mode.

    [ You probably wouldn’t believe me if I said I proofread these things before posting them, but I do. 🙂 Thanks again. -Alex ]

  • Using visual effects 2010 if I go to do the step into command for [std:: << cout value;] the debugger opens a read only code called ostream. If I keep trying the step into command more read only code comes up.  Is there a way to change this in settings and I just can’t find it or do I need to get another debugger program. Using the step out command it also opens another read only code file called crtexe.c

  • It was a very helpful post Alex, Thanks 🙂

  • Kyle

    i’m using codeblocks 13.12 and i cannot find the "step over" option in the debug menu. do you know where i can find it? thanks

  • David

    i am using Xcode for mac and when i open the debug dropdown menu the step into line is there but not available to select.  is there a certain line i must have highlighted or would there be any other problem? thanks 🙂

    • Alex

      I can’t answer this since I don’t have XCode. Perhaps another reader can help?

      Make sure you’re compiling your program in debug mode and not release mode.

    • Nick

      You have to enable breakpoints, clicking the line number at the left of (…) each line.
      A global breakpoint disabler is available at the top of the debugger window.

      • Aaron

        I enabled breakpoints and I hit run. It unlocked the debugger "step into" and all that but it gives you a weird window that I can’t even understand. Anybody know what this stuff means:

        Debug`main:
            0x100000f50 <+0>:  pushq  %rbp
            0x100000f51 <+1>:  movq   %rsp, %rbp
            0x100000f54 <+4>:  subq   $0x10, %rsp
            0x100000f58 <+8>:  movl   $0x5, %edi
            0x100000f5d <+13>: movl   $0x0, -0x4(%rbp)
        ->  0x100000f64 <+20>: callq  0x100000f20               ; printValue(int) at main.cpp:4
            0x100000f69 <+25>: xorl   %eax, %eax
            0x100000f6b <+27>: addq   $0x10, %rsp
            0x100000f6f <+31>: popq   %rbp
            0x100000f70 <+32>: retq

        • Alex

          Looks like assembly code.

          This is what I might expect to see if you tried to debug a release build instead of a debug build.

          • Aaron

            I think you might be right. I went to "debug">"debug workflow">and there was this thing called "always show disassembly". I unchecked it and I was able to debug everything fine. Not sure if this is related to the build or not but if it is good call.

    • OA

      Here’s a youtube video that explains Xcode 7 debugging:

      https://www.youtube.com/watch?v=VsenB1fTgXk

  • SomeGuy

    Hi Alex and thx for the great tutorials.I have a question: I am a little confused with step out.
    when i use the step out in the std::cout << value; //command in the Print Value Function(),
    It executes the command! I thought it shouldn’t…. 🙁

    • Alex

      Step out executes all the commands in the function, and then returns control to you when the function has returned to the caller. I see that the lesson text is unclear in this regard, so I’ll update it.

  • Tomás Antunes

    Hi, these tutorials are great.

    I’d just like to point out in section "Run to cursor" there is a small inconsistency with the variable name: "value" is referred to as "nValue".

    Cheers

  • Benjamin Collins

    I’m STILL laughing at "Hello, word!"

  • andy mackeroon

    Hi, thanks for the tutorials. Having done plenty of tutorials like this, for various scripting languages and packages, I like they way you have started with a few juicy commands like cout and cin and functions, and then went on to the more prosaic stuff of how the compiler works, like #include and #define and debugging, before going back to flow control, loops and covering the rest of the standard commands. Usually most ppl who prepare tutorials would cover printing to the screen "hello world", variables, functions, flow control, loops, then go on to the stuff about how the compiler works and compile time directives and program structure, but as that stuff isn’t as exciting as learning new commands, some people mightn’t keep with it long enough to get to them. The way you have structured the tutorial makes me want to plough through that….OK I’ll say it boring stuff, to get back to the good stuff, don’t know if that was intentional but it’s working for me.

  • Edward

    First, Thank you Alex for this fantastic C++ tutorials.  I’m a newbie to coding and thoroughly enjoying your materials.  The way you explain things are quite succinct, clear and to the point.  I truly admire your writing style.

    Anyway, in case someone is having an issue getting the debugger working in Code::Blocks (e.g. debugging not executing or console windows console suddenly closing), it may be due to your anti-virus software. If it is, my suggestion is to exclude your Code::Blocks install directory from being scanned by your anti-virus.  This is how I resolved my debugger issue which eventually stopped me from banging my head on the computer desk.

  • yoh

    Hey Thanks for this amazing blog But i got a question about debugging

    Does debugging help me In anyway if i was using a command line (since i dont think most of the features would be there in a command line)? Oh and if so can you recommend me one? (I only got 128mb of ram, Im saving up for new one don’t worry  xD)

    • Alex

      Yes, you can debug console application via the command line. It’s not as easy as via an IDE, but it can be done. Check out the GDB debugger.

  • Hugo

    Would it be possible for you to add a basic "how to debug using gdb" in this section for those of us running from the command window?

  • jason paulaskas

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    void thank_you()
    {cout<<"i just wanna thank this adorable site "<<endl;
    }
    int main (){
    thank_you();
    cout<<"guys this is the best page i ever seen to learn people like me \n who love learning programming \n but they <<"dont know how to start "<< endl<<endl;
    cout<<"bless you guys"<<endl;
    return 0;

  • Devashish

    Hey Alex, in this section, function printValue() is written PrintValue() in some places. Fix that. Great Tutorials 🙂

  • Roberto

    I get the following error when trying to degub

    warning: GDB: Failed to set controlling terminal: Operazione non permessa

    someone can help?

  • Roberto

    I’ve switched to gnome terminal. under SETTINGS -> Environment -> Terminal to launch:

    gnome-terminal -disable-factory -hide-menubar -t $TITLE -x

    I still get the error, but at least now the value 5 appears on the terminal; anyway I don’t think the debugger is working properly because I get the value 5 only at the end instead it should be before.

  • newbie

    Have installed gdb and Code:Blocks on Linux Manjaro.

    After setting breakpoints in the code and stepping into the program, I get the following output without having the program stop at the required breakpoint:

    Selecting target:
    Debug
    Adding source dir: /home/guest/Documents/Develop/Cpp/Projects/Ch01/1-11wv/
    Adding source dir: /home/guest/Documents/Develop/Cpp/Projects/Ch01/1-11wv/
    Adding file: /home/guest/Documents/Develop/Cpp/Projects/Ch01/1-11wv/bin/Debug/1-11wv
    Changing directory to: /home/guest/Documents/Develop/Cpp/Projects/Ch01/1-11wv/.
    Set variable: LD_LIBRARY_PATH=.:
    Starting debugger: /usr/bin/gdb -nx -fullname  -quiet  -args /home/guest/Documents/Develop/Cpp/Projects/Ch01/1-11wv/bin/Debug/1-11wv
    done
    Debugger finished with status 1

  • newbie

    If run gdb by itself in command prompt, I get:

    gdb: error while loading shared libraries: libncursesw.so.6: cannot open shared object file: No such file or directory

    • newbie

      Getting the same behaviour on Geany with Debug plugin loaded:

      gdb: error while loading shared libraries: libncursesw.so.6: cannot open shared object file: No such file or directory

      See Error dialog with message:

      "GDB died unexpectedly with status 32512"

      Seems there is some problem with GDB.

      Have gdb 7.10.1-1, geany 1.26-2, geany-plugin 1-26-1 installed

  • AG

    Getting strange error I can’t fix, runs debugger up until return line then gets the following error:

    Cannot open file: ../../../../src/gcc-4.7.1/libgcc/unwind-sjlj.c

    • AG

      PS)
      I’m using Code::Blocks and the problem is occurring when I press step into;

    • AG

      The project works later however if I comment out a cin statement… please help, I’m so lost right now;

    • Alex

      I’m not sure what the issue is here, sounds like a bug in the GDB debugger itself.

      This is probably a better question for Google than these forums. Maybe another user has found a solution.

      • AG

        I’ve been looking everywhere, including asking on a few sites but haven’t gotten anything back… (I’ll keep waiting though) It sounds like its a problem with the debugger’s settings. I’ve noticed on the stack window after I get to the point where it doesn’t work a new function shows up in red: "_Unwind_SjLj_Unregister (fc=0x69fe7c)"

        Thank you so much for your speedy response, I appreciate it! 🙂

  • JL

    When I Step into (Code::Blocks) the console windows opens with the following message:

    warning: GDB: Failed to set controlling terminal: Operation not permitted

    And If I ‘step into’ until the end of the program I never see any output to the terminal.

    Debugger:

    Building to ensure sources are up-to-date
    Selecting target:
    Debug
    Adding source dir: /home/m/CBprojects/debuuging/
    Adding source dir: /home/m/CBprojects/debuuging/
    Adding file: /home/m/CBprojects/debuuging/bin/Debug/debuuging
    Changing directory to: /home/m/CBprojects/debuuging/.
    Set variable: LD_LIBRARY_PATH=.:
    Starting debugger: /usr/bin/gdb -nx -fullname  -quiet  -args /home/m/CBprojects/debuuging/bin/Debug/debuuging
    done
    Registered new type: wxString
    Registered new type: STL String
    Registered new type: STL Vector
    Setting breakpoints
    Debugger name and version: GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
    At /home/m/CBprojects/debuuging/main.cpp:10
    At /home/m/CBprojects/debuuging/main.cpp:5
    At /home/m/CBprojects/debuuging/main.cpp:6
    At /home/m/CBprojects/debuuging/main.cpp:11
    At /home/m/CBprojects/debuuging/main.cpp:12
    Cannot open file: libc-start.c              //Error in red highlight.
    At libc-start.c:321

  • subhendu rana

    your tutorial is good. I am using code block.When i am running that particular program given ,it’s printing ‘5’ in console window but when I am checking with  step commands,it’s not showing ‘5’ in console window ,it is  showing "warning GDB:Failed to set controlling terminal:operation not permitted"

    include <iostream>
    using namespace std;
    void print(int);
    int main()
    {
        cout<<"hello world"<<endl;
        print(5);
        return 0;
    }
    //linked up with other file  
    #include<iostream>
    void print(int val)
    {
    std:: cout<<val;

    }

  • moopet

    This sounds like a stupid question, but I do not understand what this means: return control
    "step into enters the function and returns control at the top of the function"
    "at this point, printValue() has finished executing and control is returned to main()"
    "returns control to you"

    I thought I might see it somewhere in the Output window of Visual Studio 2015. But the output window tells me "’Turtorial_01.exe’ (Win32): Loaded ‘C:\Windows\SysWOW64\bcryptprimitives.dll’. Cannot find or open the PDB file.".

    All I see is a "diagnostics tool" window that tells me "Step Recorded" and the time it took.

  • Hey Alex, i love your guide but i am a total noob and ran into a problem. When i press "step into" in codeblocks, at the bottom of the screen at the debugger option it just writes failed. Why and how could i fix it?
    p.s. “failed” is the response for everyoption, like continue and run to cursor.

    • Alex

      I’ve never heard of this happening before. My advice would be to use google to see if you can find anyone else having the same issue. Maybe they’ll know what the fix is.

      One thing to check though: are you using a debug build configuration?

  • I actually had to download another compiler/debugger combo, the previous was probably bad/bugged. But this Works now ^^

  • Nyap

    the integrated debugger in codeblocks is terrible

    • Nyap

      and btw, isn’t "step out" basically the same as "run"? or are they different? I’d try them both out to see if there’s any difference, but as I said, codeblocks debugger is broken

      • Alex

        Step out runs the current function and returns control back to you once the function exits. Run runs until the end of the program.

        If you are inside of main(), they are essentially identical, but from within a subfunction, they exhibit different behaviors.

  • Rojava

    I found a solution to stop the debugger from stepping into the code for operator<<. Here’s the solution:

    It requires editing the default.natstepfilter file.

    This applies to Visual Studio 2012 and up. Older versions require changing values in the registry (Google how-to for older versions -- though you should REALLY upgrade!).

    Locate the default.natstepfilter file:

    Above filepaths are for Visual Studio 2015. It should be easy to locate your own version. Here are the version numbers for the different versions of Visual Studio:

    When you find the file, open the file with an editor (I used Notepad++).
    You may need to run as adminstrator!

    Add this line to the file (along with the other lines already listed):

    Note: Above line does not only apply for operator<< though. It applies to the whole std:: library, and since the above operator is a part of the standard library, it’ll obviously apply for that as well. The dot and the asterisk in std::.* indicates that.

    So the next time you run the debugger, it won’t step into operator<< (or anything else in the std:: library for that matter) as seen by the "NoStepInto" value. It basically tells the debugger to step over the matched function (in this case, the operator<<).

    You can specify any function to step over by listing them as non-user code in the default.natstepfilter file.

    I hope it helps!

  • Bob

    What I’ve come to find out is that you have to start a project otherwise some features won’t be available on CodeBlocks. I don’t know why this is… The debugger didn’t work until i rewrote my file, and included it in a project.

  • bert

    FYI, in the links after the conclusion, the back link does not point to the previous lesson.  It points to the current lesson.

    thanks!

  • hp

    Hi i still do not understand how  5 - 3 = 2, how come it is 8 as you said above?

    • Alex

      The function is named add(), so clearly the intent is to add the numbers, not subtract them. The add() function has a typo where the minus operator is being used instead of the plus operator, so the result of add(5,3) is 2 instead of the expected 8.

  • OA

    For xCode 7 Users:

    My debug menu in xCode 7 was greyed out, this YouTube tutorial was a good explanation:

    https://www.youtube.com/watch?v=VsenB1fTgXk

  • Garry E

    Alex:
    Using Visual Studio 2015. Debugged printValue sketch and everything in tutorial went according
    to plan up to the point of entering "Step out".After that a new screen with over 200 lines
    of code popped up. My original screen was titled ConsoleApplication7.cpp . The new one was simply called
    Miscellaneous. The cursor was at line 64 in this program. After fumbling around a bit I found that if I
    repeatedly clicked "Step into" the cursor walked down the page and eventually ConsoleApplication7 came
    back. The figure 5 did appear in the console output window after "Step out" was applied. After restoring
    the ConsoleApplication7 screen with "Step into" clicks the output screen was blank. Is there an easy
    answer?

    Garry E

    • Alex

      Could have been something from the C++ standard library. Sometimes the debugger will pop into there and walk through all kinds of crazy obtuse code before returning back to your code. When that happens, an additional step out normally returns you to your code.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter