GDB Conditional Breakpoints

Last week we looked at setting breakpoints in GDB. All well and good.

But what if you have a large loop running and you only want to look at what’s happening as it nears the end? Do you really have to step through 99 iterations in a 100 item loop?

Of course you don’t. Step forward the conditional breakpoint.

Set a conditional breakpoint using a condition

In GDB you can specify a condition in the programming language you are debugging and apply it to any breakpoint. Let’s stop a loop at the 99th iteration (I’m debugging C/C++, so my conditions are written in C/C++):

(gdb) b Message.cpp:112 if i == 99

That’s all there is to it.

To ensure gdb stops execution, use the first line of code inside the loop as the stopping point, not the loop itself.

You can also specify a condition on an existing breakpoint by using the breakpoint number as a reference:

(gdb) cond 3 i == 99

And remove a condition from a breakpoint using:

(gdb) cond 3
Breakpoint 3 now unconditional.

That’s great! What else can you do?

Pretty much anything you like! Just write the condition exactly as if you were testing for it in your code, e.g.:

(gdb) cond 1 strcmp(message,"earthquake") == 0
//stop if the array message is equal to 'earthquake'
(gdb) cond 2 *p == 'r'
//stop if the char* pointer p points to the letter 'r'
(gdb) cond 3 num < 0.75
//stop while the float num is less than 0.75

Conditional breakpoints covered and your efficiency increased, all in less than 5 minutes!

GDB Breakpoints

Today we’re going to take a quick look at the humble breakpoint in GDB.

You can set a breakpoint:

  • before you run the program in GDB
  • if you interrupt GDB with CTRL-C

Positioning your breakpoints

Set a breakpoint using the handy shortcut ‘b’ followed by the location. There are lots of ways to specify the location, but the most common are:

(gdb) b MessageSender.cpp:118

Pattern: filename:linenumber. Nice and simple. Puts a breakpoint at line 118 in the file MessageSender.cpp

(gdb) b 267

Pattern: linenumber. Puts a breakpoint at line 267 in the current source file. If execution has not started, the breakpoint will be inserted in the main program file.

(gdb) b main

Pattern: functionname. Puts a breakpoint at the beginning of the named function. For C++  class methods, see below.

(gdb) b Message::sendMessage

Pattern: classname::method. Puts a breakpoint at the beginning of the named method. Use tab after the :: to display a list of available methods.

(gdb) b MessageParser.c:getLen

Pattern: filename:function. Puts a breakpoint at the beginning of the named function in the file specified (useful if there is any ambiguity caused by functions with the same name).

Viewing and deleting breakpoints

To see all your breakpoints in a numbered list, type:

(gdb) i b

Delete them all with:

(gdb) d

Or specifically with the breakpoint number from the list:

(gdb) d 4

Preserve your breakpoints

Don’t quit GDB. Just type CTRL-C and then ‘r’ (for run). This will restart your program from the beginning, leaving all your breakpoints intact. Lovely!

 

Creating Your First C++ Program in Eclipse

Have you seen my C++ Eclipse Masterclass
It’s a series of professional video and text tutorials on using C++ and Eclipse CDT.

This is a tutorial on creating and understanding a ‘Hello World’ program in C++ using Eclipse.

Why? Because in the majority of my other C++ tutorials I will be using Eclipse as the IDE (integrated development environment), and building on a basic project such as this.

I program on Fedora Linux, not Windows, so although your screenshots may differ slightly to mine, Eclipse runs quite happily on both.

Setup

There’s a wealth of information on the Eclipse website that tells you how to install Eclipse for your operating system, but the heads up if you’re a Fedora user is just switch to root (or use sudo) and run:

yum install eclipse-cdt

Create your project

Open eclipse (you’ll find it in the Applications > Programming menu), and if this is the first time you have used it, accept the default workspace and close the welcome window.

Then go to:

Window > Open Perspective > Other > C/C++

This opens the C++ ‘perspective’ in Eclipse, which is a fancy way of saying it makes available the windows and options you need to develop C++ programs.

Now create your first program with:

File > New > C++ Project

Name it Hello, and select the project type as Hello World C++ Project (Figure 1).

create project window
Figure 1: Create a Hello World C++ Project

Click next and accept all the defaults in the Basic Settings window. Click next and again accept all the defaults in the Select Configurations window. Click Finish.

Eclipse will create your project and project file and return you to the main C++ view. You should now be able to see your ‘Hello’ project on the left hand side of the screen, and the contents of the Hello.cpp file in the main window. If you expand the project folder on the left, and then expand the ‘src’ folder underneath it, you will see the location of your program file, Hello.cpp (Figure 2).

hello world project
Figure 2: Your Hello World Project

Your project in action

Now all you have to do is hit ‘Run’ (it’s that little green button that looks like a play symbol).

Note: Eclipse may be set to NOT build automatically, in which case you will get an error about the binary not being found. If this happens, select Build (the hammer icon) before trying to Run.

You should see “!!!Hello World!!!” in the console area at the bottom of the screen (Figure 3). Note that if you prefer a pop-up console window, you can right click and select the ‘Detached’ option on the console tab. Even if you close the window, it will reappear next time you run the program.

console output
Figure 3: Console output

That’s great, but what does it all mean?

Let’s just run through the contents of the Hello.cpp file, so you have an idea of what you have created.

The first 7 lines are just comments. They were created for you by Eclipse and you can edit these to your heart’s content. What’s included at the top of a cpp file varies widely between companies and also depends on personal preference, but bear in mind that the point of the comments is to tell the next person that comes along a little bit about what this file contains.

The first two lines of actual code are:

#include <iostream>
using namespace std;

Any line that starts with a # character is called a ‘preprocessor directive’. The preprocessor makes any requested modifications to your source code before passing it to the compiler. In this example, line 9 is telling the preprocessor to include something called ‘iostream’, which refers to a header file that allows our program to utilize the input/output methods in the iostream library.

I will talk a little more about the preprocessor in a future tuturial, but for now you can look at this line as a succinct way to include pre-existing code.

Line 10 makes use of the using directive to tell the compiler that we are using functions from the standard namespace.

Eh?

OK, a namespace is basically a collection of classes and functions grouped together under an umbrella and given a name. In this case the name is std, and it covers all the things you might want to use from the C++ standard library. Namespaces help resolve the potential issue of classes and functions having the same name and thus causing redefinition errors when you try to compile your program.

In our example, the functions we are using from the standard library are cout and endl. If you didn’t have line 10 in your source file, you wouldn’t be able to use these, because they would not be in scope, or in other words, the compiler would not know what on earth you were referring to*.

Next we have:

int main() {
    cout << "!!!Hello World!!!" << endl;
    return 0;
}

This is the most important part of the file – it’s referred to as the main function and is where our program starts and ends. main is defined only once for any C++ (or C) program, and the name is always all lower-case.

It contains two statements inside a set of curly brackets. The first uses the function cout to print the ‘Hello World’ text to the screen (or standard output), and finishes with endl, to declare an end of line character (the equivalent of pressing the return key after typing in a sentence).

The second statement returns a zero when the program exits. Traditionally a zero return means that the program has executed without errors. It is required here because the main function return type is declared as int (short for integer), meaning a whole number of some value must be returned when the program exits.

Tell me what I’ve learnt

Well, that just about covers it. Of course, you can dig into the details of just these few lines of code and read a huge amount on the hows and whys of it all, but to summarize what this basic tutorial covers, you should have done the following:

1) Created a Hello World C++ program in Eclipse.
2) Run that program and seen the output in the console window.
3) Identified the different parts of the program: comments, preprocessor directive and code.
4) Understood the importance of the main function being our program’s entry and exit point.
5) Noted the use of the std namespace to allow us access to the functions cout and endl.
6) Appreciated the use of these functions to output a text message to the screen.

Phew! That’s enough for today. Look out for the next C++ tutorial, coming soon.

*An alternative to the using directive at line 10 is to qualify each std method with its namespace when it appears in the code, i.e.:

std::cout << "!!!Hello World!!!" << std::endl;

This is considered a better way of doing things, but typing std:: over and over can be a little laborious, hence the widespread use of the using directive on line 10. If you are after more detail, there is a good explanation of this at the C++ FAQ here.