vs 自定义变量的显示规则
1. 自定义结构体或者类在vs变量窗口显示带来的问题
struct Marray
{
int *data;
int length;
};
首先定义一个数组结构体,data指向一块内存,length是这个数组的大小
然后编写如下代码
#include <stdio.h>
#include <stdlib.h>
#define ARRAYSIZE 3
struct Marray
{
int *data;
int length;
};
int main(int argc, char* argv[])
{
struct Marray arr;
arr.data = (int*)malloc(sizeof(int) * ARRAYSIZE);
arr.length = ARRAYSIZE;
arr.data[0] = 1;
arr.data[1] = 2;
arr.data[2] = 3;
printf("hello word\n");
return 0;
}
在vs中arr这个变量会如何显示
但是我们实际上想让他把data的三个元素都显示出来,这样子便于调试发现问题
vs给我们提供了自定显示规则的方法,编写vs支持的xml文件,官方叫做natvis文件
这个文件有两种添加方式:
- 一种是直接放在vs的安装目录 %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers
- 一种是在项目中添加
也就是一种是全局的,一个是只生效这个项目中的
2. natvis文件的编写
natvis文件是xml格式文件,遵循xml语法。
2.1 xml的转义字符
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 双引号
如果在编写时用到这些符号需要转义
2.2 natvis语法
2.2.1 声明部分
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
</AutoVisualizer>
这三行固定这么写就行。第一行是xml文件的声明,第二行的vs命名空间的声明
2.2.2 类型指定
Type 标签是用来指定需要可视化类型的标签,他有一个属性是Name用来指定要自定义可视化的类型
如要指定我们刚才的Marray类型
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
</Type>
</AutoVisualizer>
2.2.3 顶级可视化显示
DisplayString标签是用来显示变量标签用的。
如遇到 Marray 我就让vs显示 hello array
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
<DisplayString>hello array</DisplayString>
</Type>
</AutoVisualizer>
vs中的展示
DisplayString 可以显示这个结构体成员的值 只需要在成员变量上加上 '{}'就可以转义
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
<DisplayString>size={length}</DisplayString>
</Type>
</AutoVisualizer>
2.2.3 类型展开
Expand 是用来做类型展开的标记
Item 是Expand的子标记可以用来展示一个项
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
<DisplayString>size={length}</DisplayString>
<Expand>
<Item Name="[size]">length</Item>
<Item Name="test">"hello"</Item>
</Expand>
</Type>
</AutoVisualizer>
可以看到Item标签的Name属性是展开项的名称,item的值不能像DisplayString可以用{}展开变量,item标签只能显示一个值,这个值可以是成员变量(这个不能加{})
2.2.3.1 连续内存的展开
ArrayItems是连续内存的列表展开,只需要内存的指针和数组大小就行
这个标记很适合现在的Marray结构的展开
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
<DisplayString>{{ size={length} }}</DisplayString>
<Expand>
<Item Name="[size]">length</Item>
<ArrayItems>
<Size>length</Size>
<ValuePointer>data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
ValuePointer标签是填内存的值
size是数组的大小
2.2.3.2 程序展开
CustomListItems 是可执行程序的展开的标签
Exec 标签可以执行程序
Loop 循环
Break 跳出循环
Variable 定义变量
Condition 属性是条件属性
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Marray">
<DisplayString>{{ size={length} }}</DisplayString>
<Expand>
<CustomListItems>
<Variable Name="i" InitialValue="0"/>
<Loop>
<Break Condition="i >= length"/>
<Item Name="[{i}]">data[i]</Item>
<Exec>i = i + 1</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
</AutoVisualizer>
2.2.4 自定义展开子元素
可以创建人工子元素,这个标签要在标签中使用
我们定义一些测试结构
#define ARRAYSIZE 3
struct Marray
{
int *data;
int length;
};
struct MStruct
{
int test;
struct Marray _arr1;
struct Marray _arr2;
};
我们需要将MStruct结构展开
测试代码
int main(int argc, char* argv[])
{
struct MStruct m;
m._arr1.data = (int*)malloc(sizeof(int) * ARRAYSIZE);
m._arr1.length = ARRAYSIZE;
m._arr2.data = (int*)malloc(sizeof(int) * ARRAYSIZE);
m._arr2.length = ARRAYSIZE;
m._arr1.data[0] = 1;
m._arr1.data[1] = 2;
m._arr1.data[2] = 3;
m._arr2.data[0] = 4;
m._arr2.data[1] = 5;
m._arr2.data[2] = 6;
printf("hello word\n");
return 0;
}
结构展开的编写
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="MStruct">
<Expand>
<Item Name="test">test</Item>
<Synthetic Name="_arr1">
<DisplayString>{{size = {_arr1.length}}}</DisplayString>
<Expand>
<Item Name="[size]">_arr1.length</Item>
<ArrayItems>
<Size>_arr1.length</Size>
<ValuePointer>_arr1.data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<Synthetic Name="_arr2">
<DisplayString>{{size = {_arr2.length}}}</DisplayString>
<Expand>
<Item Name="[size]">_arr2.length</Item>
<ArrayItems>
<Size>_arr2.length</Size>
<ValuePointer>_arr2.data</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
</AutoVisualizer>
Synthetic 标签可以自定义自己的标签,对比item标签,Synthetic 标签可以有自己的DisplayString顶层视图和Expand的展开项。理论上使用这个可以无线递归子结构
官方文档
https://docs.microsoft.com/zh-cn/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022