Search

3.6 — Using an integrated debugger: Stepping

When you run your program, execution begins at the top of the main function, and then proceeds sequentially statement by statement, until the program ends. At any point in time while your program is running, the program is keeping track of a lot of things: the value of the variables you’re using, which functions have been called (so that when those functions return, the program will know where to go back to), and the current point of execution within the program (so it knows which statement to execute next). All of this tracked information is called your program state (or just state, for short).

In previous lessons, we explored various ways to alter your code to help with debugging, including printing diagnostic information or using a logger. These are simple methods for examining the state of a program while it is running. Although these can be effective if used properly, they still have downsides: they require altering your code, which takes time and can introduce new bugs, and they clutter your code, making the existing code harder to understand.

Behind the techniques we’ve shown so far is an unstated assumption: that once we run the code, it will run to completion (only pausing to accept input) with no opportunity for us to intervene and inspect the results of the program at whatever point we want.

However, what if we were able to remove this assumption? Fortunately, we can. Most modern IDEs come with an integrated tool called a debugger that is designed to do exactly this.

The debugger

A debugger is a computer program that allows the programmer to control how a program executes and examine the program state while the program is running. 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 (logic) errors.

The power behind the debugger is twofold: the ability to precisely control execution of the program, and the ability to view (and modify, if desired) the program’s state.

Early debuggers, such as gdb, were separate programs that had command-line interfaces, where the programmer had to type arcane commands to make them work. Later debuggers (such as early versions of Borland’s turbo debugger) were still standalone, but came with their own “graphical” front ends to make working with them easier. Most modern IDEs available these days have an integrated debugger -- that is, a debugger uses the same interface as the code 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 use screenshots from Microsoft Visual Studio (and we’ll cover how to do everything in Code::Blocks as well), you should have little trouble figuring out how to access each feature we discuss no matter which development environment you are using, even one we’re not explicitly covering.

The remainder of this chapter will be spent learning how to use the debugger.

Tip

Don’t neglect learning to use a debugger. As your programs get more complicated, the amount of time you spend learning to use the integrated debugger effectively will pale in comparison to amount of time you save finding and fixing issues.

Warning

Before proceeding with this lesson (and subsequent lessons related to using a debugger), make sure your project is compiled using a debug build configuration (see 0.9 -- Configuring your compiler: Build configurations for more information). If you’re compiling your project using a release configuration instead, the functionality of the debugger may not work correctly.

For Code::Blocks users

If you’re using Code::Blocks, your debugger may or may not be set up correctly. Let’s check.

First, go to Settings menu > Debugger…. Next, open the GDB/CDB debugger tree on the left, and choose Default. A dialog should open that looks something like this:

If you see a big red bar where the “Executable path” should be, then you need to locate your debugger. To do so, click the button to the right of the Executable path field. Next, find the “gdb32.exe” file on your system -- mine was in C:\Program Files (x86)\CodeBlocks\MinGW\bin\gdb32.exe. Then click OK.

For Code::Blocks users

There have been reports that the Code::Blocks integrated debugger (GDB) can have issues recognizing some file paths that contain spaces or non-English characters in them. If the debugger appears to be malfunctioning as you go through these lessons, that could be a reason why.

Stepping

We’re going to start our exploration of the debugger by first examining some of the debugging tools that allow us to control the way a program executes.

Stepping is the name for a set of related debugger features that let us execute (step through) our code statement by statement.

There are a number of related stepping commands that we’ll cover in turn.

Step into

The step into command executes the next statement in the normal execution path of the program, and then pauses execution of the program so we can examine the program’s state using the debugger. If the statement being executed contains a function call, step into causes the program to jump to the top of the function being called, where it will pause.

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

Let’s debug this program using the step into command.

First, locate and then execute the step into debug command once.

For Visual Studio users

In Visual Studio, the step into command can be accessed via Debug menu > Step Into, or by pressing the F11 shortcut key.

For Code::Blocks users

In Code::Blocks, the step into command can be accessed via Debug menu > Step into, or by pressing the Shift-F7

For other compilers

If using a different IDE, you’ll likely find the step into command under a Debug or Run menu.

Because our program wasn’t running, when you execute the your first debug command, you may see quite a few things happen:

  • The program will recompile if needed.
  • The program will begin to run. Because our application is a console program, a console output window should open. It will be empty because we haven’t output anything yet.
  • Your IDE may open some diagnostic windows, which may have names such as “Diagnostic Tools”, “Call Stack”, and “Watch”. We’ll cover what some of these are later -- for now you can ignore them.

Because we did a step into, you should now see some kind of marker appear to the left of the opening brace of function main (line 9). In Visual Studio, this marker is a yellow arrow (Code::Blocks uses a yellow triangle). 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 to be executed is the opening brace of function main (line 9).

Choose step into to execute the opening brace, and the arrow will move to the next statement (line 10).

This means the next line that will be executed is the call to function printValue.

Choose step into again. Because this statement contains a function call to printValue, we step into the function, and the arrow will move to the top of the body of printValue (line 4).

Choose step into again to execute the opening brace of function printValue, which will advance the arrow to line 5.

Choose step into yet again, which will execute the statement std::cout << value and move the arrow to line 6.

Warning

Because operator<< is implemented as a function, your IDE may step into the implementation of operator<< instead.

If this happens, you’ll see your IDE open a new code file, and the arrow marker will move to the top of a function named operator<< (this is part of the standard library). Close the code file that just opened, then find and execute step out debug command (instructions are below under the “step out” section, if you need help).

Now because std::cout << value has executed, and we should now see the value 5 appear in the console window.

Choose step into again to execute the closing brace of function 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 three more times. 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, others may not. If your debugger does not, you may need to find a "Stop Debugging" command in your menus (in Visual Studio, this is under Debug > Stop Debugging).

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

Congratulations, you've now stepped through a program and watched every line execute!

Step over

Like step into, The step over command executes the next statement in the normal execution path of the program. However, whereas step into will enter function calls and execute them line by line, step over will execute an entire function without stopping and return control to you after the function has been executed.

For Visual Studio users

In Visual Studio, the step over command can be accessed via Debug menu > Step Over, or by pressing the F10 shortcut key.

For Code::Blocks users

In Code::Blocks, the step over command is called Next line instead, and can be accessed via Debug menu > Next line, or by pressing the F7 shortcut key.

Let's take a look at an example where we step over the function call to printValue:

First, use step into on your program until the execution marker is on line 10:

Now, choose step over. The debugger will execute the function (which prints the value 5 in the console output window) and then return control to you on the next statement (line 12).

The step over command provides a convenient way to skip functions when you are sure they already work or are not interested in debugging them right now.

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 currently being executed, and then returns control to you when the function has returned.

For Visual Studio users

In Visual Studio, the step out command can be accessed via Debug menu > Step Out, or by pressing the Shift-F11 shortcut combo.

For Code::Blocks users

In Code::Blocks, the step out command can be accessed via Debug menu > Step out, or by pressing the ctrl-F7 shortcut combo.

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

Step into the program until you are inside function printValue, with the execution marker on line 4.

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 (on line 10).

This command is most useful when you've accidentally stepped into a function that you don't want to debug.

A step too far

When stepping through a program, you can normally only step forward. It's very easy to accidentally step past (overstep) the place you wanted to examine.

If you step past your intended destination, the usual thing to do is stop debugging and restart debugging again, being a little more careful not to pass your target this time.

Step back

Some debuggers (such as Visual Studio Enterprise Edition and GDB 7.0) have introduced a stepping capability generally referred to as step back or reverse debugging. The goal of a step back is to rewind the last step, so you can return the program to a prior state. This can be useful if you overstep, or if you want to re-examine a statement that just executed.

Implementing step back requires a great deal of sophistication on the part of the debugger (because it has to keep track of a separate program state for each step). Because of the complexity, this capability isn't standardized yet, and varies by debugger. As of the time of writing (Jan 2019), neither Visual Studio Community edition nor the latest version of Code::Blocks support this capability. Hopefully at some point in the future, it will trickle down into these products and be available for wider use.


3.7 -- Using an integrated debugger: Running and breakpoints
Index
3.5 -- More debugging tactics

123 comments to 3.6 — Using an integrated debugger: Stepping

  • 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!

  • 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.

  • 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!

  • 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.

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

  • 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?

  • 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.

  • 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;

    }

  • 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

  • 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! :)

  • 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

  • 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

  • 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.

  • Roberto

    I get the following error when trying to degub

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

    someone can help?

  • Devashish

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

  • 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;

  • 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?

  • 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.

  • 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.

  • 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.

  • Benjamin Collins

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

  • 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

  • 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.

  • 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

  • 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

  • It was a very helpful post Alex, Thanks :)

  • 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

  • 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 ]

Leave a Comment

Put all code inside code tags: [code]your code here[/code]