GDB Tips and Tricks #6: Examining Data Types

It’s often the case that while stepping through code you encounter a variable that’s unknown to you. If it doesn’t appear to be relevant to the task at hand, perhaps you choose to ignore it. But if it may have some significance to the problem you’re trying to solve, you’ll obviously need to learn a bit more about it.

The first thing you might want to learn about the variable is its type. You can turn to the source code to seek this out. If the type turns out to be a struct/class, typedef, or type alias, you might need to do a bit more spelunking to fully understand what kind of data is in play.

Fortunately, gdb provides us with a couple of commands to help us out when it comes to data types – whatis and ptype

whatis

The whatis command tells us the superficial type of a variable or expression. By that I mean, it will show the type of something as it appears in code. Things like typedefs or type aliases aren’t “unrolled.” But the whatis command accepts expressions too. So if you’d like unroll a typedef or type alias, you can do so manually. Let’s see some examples.

Let’s use the following snippet of code.

struct MyStruct
{
    int x;
    MyStruct() : x(2) {}
};
 
using _IntegerValue = int;
using IntValueAlias = _IntegerValue;
 
int main()
{
    int a = 0;
    IntValueAlias b = 1;
    MyStruct c;
    return 0;
}

After we compile, launch gdb, and step into main, let’s ask gdb to tell us the types of the variables a, b, and c.

(gdb) whatis a
type = int
(gdb) whatis b
type = IntValueAlias
(gdb) whatis c
type = MyStruct

As you’d probably expect, gdb prints “int” when we ask about variable a’s type. When we ask for the type of variable b, we see “IntValueAlias”. You’ll note from the code snippet above that IntValueAlias is just a type alias for another type alias which isn’t shown in gdb’s output. When asked about the type of c, we get the struct name, “MyStruct”.

If we want to dig a bit further on the type alias, we can use whatis like so.

(gdb) whatis IntValueAlias
type = _IntegerValue
(gdb) whatis _IntegerValue
type = int

If you expect whatis to give you more detailed information about structures and classes, you’ll be disappointed to know that it doesn’t help you out. The documentation for whatis actually claims that the /M option will show class methods and that /T shows typedefs defined in a class, but I’ve never been able to get these options to do anything.

(gdb) whatis MyStruct
type = MyStruct

I should mention a couple of things about templates and whatis. The whatis command substitutes template parameters and typedefs when displaying type information for variables of template types. This means you can see pretty nasty stuff.. For example, take this snippet of code.

int main()
{
    std::string a;
    std::map<std::string, std::string> b;
    return 0;
}

If we ask gdb what the type of a is, we’ll see the following.

(gdb) whatis a
type = std::__cxx11::string

That’s not exactly what we typed in our code, but it’s workable.

What about the type of b?

(gdb) whatis b
type = std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >

As my two-year old daughter would say, “YUCK!”. Unfortunately, it is what it is and we have to work with it.

ptype

The ptype command is a bit more heavy duty than whatis. Think of it as whatis on steroids. In the case of typedefs and type aliases, ptype always unrolls them. In the case of structs and classes, ptype gives much more detailed information, which includes methods and member variables. In the case of templates, well, we get a lot more yuck.

Let’s look again at our first example.

struct MyStruct
{
    int x;
    MyStruct() : x(2) {}
};
 
using _IntegerValue = int;
using IntValueAlias = _IntegerValue;
 
int main()
{
    int a = 0;
    IntValueAlias b = 1;
    MyStruct c;
    return 0;
}

Just as we did before, let’s examine the types of variables a, b, and c. But instead of using whatis, let’s use ptype.

(gdb) ptype a
type = int
(gdb) ptype b
type = int
(gdb) ptype c
type = struct MyStruct {
    int x;
  public:
    MyStruct(void);
}

The type of a is shown as int, just as before. The type of b has been unrolled all the way down to the type of the original type alias, which is int. The type of c now shows the layout of the MyStruct struct.

I’ll spare you from a ptype example using templates. As you can imagine, a lot more information is displayed as compared to whatis.

Conclusion

Both whatis and ptype are handy tools for inspecting data types. You could certainly accomplish the same types of things manually within your IDE. But these commands allow you to keep your focus on the debugging session instead of your IDE, which hopefully means being more efficient in tracking down the source of bugs.

Leave a Reply

Your email address will not be published. Required fields are marked *

24 ÷ 3 =