Debugger Type Visualizers for C++ in Visual Studio 2012

Debugger Type Visualizers for C++ in Visual Studio 2012

Rate This
  • Comments 39

 In Visual Studio 2012, one of the new features for C++ developers is the new native type visualization framework (natvis) added to the debugger which allows customizing the way data types are displayed in debugger variable windows (e. g. autos, watch, locals, and data tips). For those who are familiar with the autoexp.dat file that has been used in earlier versions of Visual Studio, this new visualization framework supersedes that and offers xml syntax, better diagnostics, versioning and multiple file support.

To illustrate how type visualizers help make it easier to inspect objects, the following screenshot shows how a std::vector<int> is displayed in the debugger without any type visualizers:

                  

The view without type visualizers is not user-friendly and hard to read. You cannot easily see the size or the elements of the vector. Visual Studio ships with type visualizers for common data types such as std::vector and the default view for a std::vector using type visualizers is much more useful:

 

 

Creating a type visualizer for a custom data type

If you have a custom data type you can easily override Visual Studio’s default view of it using this framework and make it easy to inspect objects of that type. To demonstrate how you can do this, let’s go through the process of creating one for the simple rectangle type shown in the code snippet below (the dummy code that uses it is also included):

struct Rectangle

{

    int height;

    int width;

};

 

int _tmain(int argc, _TCHAR* argv[])

{

    Rectangle myRectangle = { 3, 4 };

    Rectangle myRectangle2 = { 4, 4 };

    return 0;

}

 

The debugger’s default view of the “myRectangle” variable which we are going to customize is as follows:

 

 

Type visualizers for C++ types are specified in .natvis files. A natvis file is simply an xml file (with .natvis extension) that contains visualization rules for one or more types. At the start of each debugging session, Visual Studio processes any natvis files it can find in the following locations:

  • -         %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access)
  • -         %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\
  • -         VS extension folders

 

As the first visualizer for the rectangle type, create a new file called “rectangle.natvis” containing the following xml (explained further below) and save it in “My Documents\Visual Studio 2012\Visualizers” folder.

 

<?xml version="1.0" encoding="utf-8"?>

<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

    <Type Name="Rectangle">

        <DisplayString>A rectangle with height = {height} and width = {width}</DisplayString>

    </Type>

</AutoVisualizer>

 

After the file is saved, start debugging the code snippet we have for the type and view the ‘myRectangle’ variable in the watch window. The debugger now displays the object as:

 

 

 

To explain the xml snippet in the natvis file, each Type element represents a visualizer entry for a type whose fully qualified name is specified in the Name attribute. DisplayString element customizes the string shown in the value column for the type. It accepts a mixture of arbitrary strings and expressions. Everything inside curly braces ({height}, {width} above) is interpreted as an expression and gets evaluated by the debugger.

Let’s assume you would like to enhance this view when the rectangle is actually a square and display something different. You can use the Condition attribute, which is available for many visualizer elements, to have if-else logic in the visualization entry. Add the following highlighted line to the visualizer entry and save the file:

<?xml version="1.0" encoding="utf-8"?>

<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

    <Type Name="Rectangle">

        <DisplayString Condition="height == width">This is a square with sides of {height}</DisplayString>

        <DisplayString>This is a rectangle with height = {height} and width = {width}</DisplayString>

    </Type>

</AutoVisualizer>

 

Note that it is NOT necessary to restart Visual Studio for it to pick up the changes to a visualizer. Once you start the debugger and add ‘myRectangle’, ‘myRectangle2’ variables to the watch window, you can see a different string is shown for a rectangle object that is actually a square:

 

 

Just as you can customize the value of the variable shown in the value column, you can also customize the view of the child elements when the variable is expanded in the debugger windows. Let’s say you would like to see the area of a rectangle in addition to its height and width during debugging. The Expand node, which allows you to define child elements for a type, can be used for this purpose. Add the highlighted section below to the visualizer entry and save the file:

<?xml version="1.0" encoding="utf-8"?>

<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

    <Type Name="Rectangle">

        <DisplayString Condition="height == width">A square with sides of {height}</DisplayString>

        <DisplayString>A rectangle with height = {height} and width = {width}</DisplayString>

        <Expand>

            <Item Name="height">height</Item>

            <Item Name="width">width</Item>

            <Item Name="area">height * width</Item>

        </Expand>

    </Type>

</AutoVisualizer>

 

As you can guess, each Item node defines a single child element whose name is given by the Name attribute and whose value is given by the expression in the node text. This is the updated view with the area element added:

 

More information

This blog post covers just a little bit of what you can do with the new native type visualization framework in the Visual Studio debugger. To learn more about it you can check out our sample page on msdn where we have more examples, xml syntax reference, instructions on turning on diagnostics and deploying visualizers via VSIX packages.

 

 

Cagri Aslan, Developer on the Visual Studio Debugger team.

  • Cagri and Stephan, yes I'm using VS11 RC. I just tried another repro and was confused when std::array did indeed work - then I remembered that my earlier test was a VS2010 solution opened in VS11 without upgrading. I'd still expect this to work though.

    The array-of-vectors thing is broken whether using a native 11RC project or not though. If you're using a VS11 project, it has to be a normal array rather than std::array, because as just described you won't see the _Elems pointer otherwise.

    I'll stick these on Connect.

  • @S. Colcord> Regarding your suggestion, yes, that is one of the options considered. Feel free to file it with uservoice to help us gauge our options. Thanks for your feedback.

  • natvis execute item even if condition fails. My boost::variant implementation (github.com/.../boost.natvis) doesn't work for boost::variant<int, bool>, because it try cast third default parameter and fail.

  • Arkadiy Shapkin: You should probably imitate std::tuple's visualizer, in particular how it handles the internal type std::_Nil.

  • Stephan T. Lavavej: Thanks, I'll try.

    BTW Steaphan, why operator -> was added to natstepfilter for CComPtr, but not for shared_ptr, weak_ptr?

  • I thought about telling the debugger to skip over other STL operations, but I went with just std::forward and std::move which are (a) extremely common and (b) never ever interesting (they are the equivalent of casts). op* and op-> are potentially interesting, especially if we add debugging checks to shared_ptr/unique_ptr (which are on my todo list).  You can add them to your own natstepfilter if you don't want to see them.

  • Stephan, I think std::[w]string c_str()/data() should be added to natstepfilter because it doesn't contain debugging checks and often called in function arguments.

  • Adding something to the default natstepfilter is a very aggressive move, because I don't believe there's an easy way for users to undo it (hacking the file requires admin access), and it may be surprising when the debugger just decides to skip stuff.

  • Current implementation have serious problem for complex linked list types:

    connect.microsoft.com/.../problem-with-debugger-visualizer-tn-macros-substitution-for-linked-list-elements

    and also minor issue with spaces in C++ identifier

    connect.microsoft.com/.../casting-complex-types-doesnt-work-correctly-in-c-debugger-visualizers

Page 3 of 3 (39 items) 123