[英]Circular Double Linked list visualization using natvis
我想為雙鏈表編寫一個natvis 可視化工具。 列表沒有存儲計數節點,簡單的方法效果不佳,因為擴展永遠不會停止(next 永遠不會為空,列表的最后一項指向列表根)。
<Type Name="TListBidir<*>">
<Expand>
<LinkedListItems>
<HeadPointer>next</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>($T1 *)this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
我希望我能夠在 NextPointer 中添加一個 Condition 屬性,將它與列表頭進行比較,但是由於 NextPoint 在節點的上下文中被評估,我不知道將它與什么進行比較:
<NextPointer Condition="next!=XXXXXXXXX">next</NextPointer>
這是以前(2010 年)可視化工具的樣子,使用跳過指令,因為#list 正在自動處理:
#list
可以防止無限遍歷,並且可以優雅地處理循環列表。 此外,您可以使用skip:
表達式來表示不應報告的哨兵節點。 雖然名字暗示節點會被跳過,但它實際上會導致遍歷停止,所以如果你的哨兵節點是第一個你應該在它之后開始遍歷。
TListBidir<*,*,*>{
children
(
#list(
head: ((($T2 *)&$c)->next),
next: next,
skip : &($c)
): (($T1 *)(&$e))
)
}
我如何在 natvis 中向調試器解釋它一旦再次到達根元素就應該停止擴展列表?
我有一個類似的問題,不是循環列表,而是最后一個指向自身的哨兵節點,並提出了一個可能適合您需求的有趣解決方案:您可以使用三元運算符來偽造一個真正的終止。 <NextPointer>
的表達式可以是您可以用普通 C 編寫的任何內容,因此您可以在其中進行真正的計算(但遺憾的是,沒有遞歸)。
(請注意,不允許將Condition
屬性放在<NextPointer>
,因此三元運算符是在那里完成條件的唯一方法。)
所以在我的情況下,列表是這樣終止的:
<LinkedListItems>
<HeadPointer>this</HeadPointer>
<NextPointer>next != this ? next : 0</NextPointer>
<ValueNode>items</ValueNode>
</LinkedListItems>
在您的情況下,如果每個節點都有一個指向其容器的指針,您可以使用它來與頭節點進行比較:
<LinkedListItems>
<HeadPointer>container->head</HeadPointer>
<NextPointer>next != container->head ? next : 0</NextPointer>
<ValueNode>items</ValueNode>
</LinkedListItems>
或者,沒有>
實體並用更傳統的 C 編寫,這相當於:
next != container->head ? next : NULL
但是,如果您沒有某種container
反向指針,那么您可能不走運,因為無法通過僅查看循環鏈表中的單個節點來回答它是否有效地“最后”節點。
您可以使用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->next_elem</Exec>
</Loop>
</CustomListItems>
CustomListItems
允許您將頭部保存在一個變量中,以便在遍歷列表時可以使用它。 如果您的頭部具有不同的類型,那么您需要將列表節點轉換為節點類型。
natvis 框架目前不支持沒有提供計數的循環鏈表。 如果您提供計數,它應該可以工作。 但是,如果沒有計數,就沒有什么好方法可以阻止擴張永遠持續下去。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.