简体   繁体   English

使用 natvis 的圆形双链表可视化

[英]Circular Double Linked list visualization using natvis

I would like to write a natvis visualizer for a double linked list.我想为双链表编写一个natvis 可视化工具。 The list does not have a count node stored, and the easy way does not work very well, as the expansion never stops (next is never null, the last item of the list is pointing to the list root).列表没有存储计数节点,简单的方法效果不佳,因为扩展永远不会停止(next 永远不会为空,列表的最后一项指向列表根)。

<Type Name="TListBidir&lt;*&gt;">
    <Expand>
        <LinkedListItems>
            <HeadPointer>next</HeadPointer>
            <NextPointer>next</NextPointer>
            <ValueNode>($T1 *)this</ValueNode>
        </LinkedListItems>
    </Expand>
</Type>

I hoped I will be able to add a Condition attribute the the NextPointer comparing it with the list head, but as the NextPoint is evaluated in the context of the node, I do not know what to compare it with:我希望我能够在 NextPointer 中添加一个 Condition 属性,将它与列表头进行比较,但是由于 NextPoint 在节点的上下文中被评估,我不知道将它与什么进行比较:

<NextPointer Condition="next!=XXXXXXXXX">next</NextPointer>

This is how it looked like with previous (2010) visualizers, using the skip directive, as the #list was handling this automatically :这是以前(2010 年)可视化工具的样子,使用跳过指令,因为#list 正在自动处理

#list is protected against infinite traversals and will cope gracefully with a circular list. #list可以防止无限遍历,并且可以优雅地处理循环列表。 Also, you can use a skip: expression to denote a sentinel node that should not be reported.此外,您可以使用skip:表达式来表示不应报告的哨兵节点。 Although the name implies that the node will be skipped, it actually causes traversal to stop, so if your sentinel node is first you should start traversal after it.虽然名字暗示节点会被跳过,但它实际上会导致遍历停止,所以如果你的哨兵节点是第一个你应该在它之后开始遍历。

TListBidir<*,*,*>{
    children
    (
      #list(
        head: ((($T2 *)&$c)->next),
        next: next,
        skip : &($c)
      ): (($T1 *)(&$e))
    )
}

How can I explain in the natvis to the debugger it should stop expanding the list once it reaches the root element again?我如何在 natvis 中向调试器解释它一旦再次到达根元素就应该停止扩展列表?

I had a similar problem, not with a circular list, but with a sentinel node at the end that pointed at itself, and came up with an interesting solution that might be adaptable to your needs: You could use the ternary operator to fake out a real termination.我有一个类似的问题,不是循环列表,而是最后一个指向自身的哨兵节点,并提出了一个可能适合您需求的有趣解决方案:您可以使用三元运算符来伪造一个真正的终止。 The expressions inside <NextPointer> can be anything you can write in vanilla C, so you can do real computation in there (but sadly, no recursion). <NextPointer>的表达式可以是您可以用普通 C 编写的任何内容,因此您可以在其中进行真正的计算(但遗憾的是,没有递归)。

(Note that you're not allowed to put a Condition attribute on <NextPointer> , so the ternary operator is the only way to accomplish conditions there.) (请注意,不允许将Condition属性放在<NextPointer> ,因此三元运算符是在那里完成条件的唯一方法。)

So in my case, the list terminated like this:所以在我的情况下,列表是这样终止的:

<LinkedListItems>
    <HeadPointer>this</HeadPointer>
    <NextPointer>next != this ? next : 0</NextPointer>
    <ValueNode>items</ValueNode>
</LinkedListItems>

In your case, if the nodes each have a pointer to their container, you can use that to compare against the head node:在您的情况下,如果每个节点都有一个指向其容器的指针,您可以使用它来与头节点进行比较:

<LinkedListItems>
    <HeadPointer>container-&gt;head</HeadPointer>
    <NextPointer>next != container-&gt;head ? next : 0</NextPointer>
    <ValueNode>items</ValueNode>
</LinkedListItems>

Or, without the &gt;或者,没有&gt; entities and written as more traditional C, that's equivalent to:实体并用更传统的 C 编写,这相当于:

next != container->head ? next : NULL

If you don't have some kind of container back-pointer, though, you're probably out of luck on this, since there's no way by looking at only a single node in a circularly-linked list to answer whether it's effectively the "last" node.但是,如果您没有某种container反向指针,那么您可能不走运,因为无法通过仅查看循环链表中的单个节点来回答它是否有效地“最后”节点。

You can do this with a CustomListItems element:您可以使用CustomListItems元素执行此操作:

<CustomListItems>
    <Variable Name="orig_head" InitialValue="head"/>
    <Variable Name="iter" InitialValue="first_elem"/>
    <Loop>
        <Break Condition="iter == orig_head || iter == 0"/>
        <Item>*iter</Item>
        <Exec>iter = iter-&gt;next_elem</Exec>
    </Loop>
</CustomListItems>

CustomListItems allows you to save the head in a variable so it can be used while traversing the list. CustomListItems允许您将头部保存在一个变量中,以便在遍历列表时可以使用它。 If your head has a different type then the list nodes you will need to cast it to the node type.如果您的头部具有不同的类型,那么您需要将列表节点转换为节点类型。

The natvis framework does not currently support circular linked lists without a count provided. natvis 框架目前不支持没有提供计数的循环链表。 If you provide a count, it should work.如果您提供计数,它应该可以工作。 However, without a count, there is no good way to prevent the expansion from just continuing on forever.但是,如果没有计数,就没有什么好方法可以阻止扩张永远持续下去。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM