「Graphical Debugging」(網頁)是 VisualStudio 的一個延伸模組,它的功能是可以把 C++ 與 C# 中特並類型的資料、視覺畫出來、方便在偵錯的時候觀察。官方的說明是:
Visualization of C++ and C# variables during debugging, e.g. Boost.Geometry models, containers of values, arrays of points, etc.
Heresy 最早看到是很久以前的「Boost Debugger visualizers」(網頁),最初應該是只有針對 Boost C++ Libraries 的型別來做監看的修飾,但是看來現在功能多了很多了~
Graphical Debugging 的功能主要分成四大類:
- Debugger visualizers
- 針對 Boost.Array、Boost.Container、Boost.Geometry、Boost.MPL、Boost.Polygon、Boost.Tuple 和 Boost.Variant 這些型別的資料,調整在 VisualStudio 偵錯時、監看視窗所顯示的內容格式,讓他顯示地更友善。
- Geometry Watch
- 將 2D 幾何資料用畫出來觀察。
可以同時顯示多組資料,所以可以更方便地以視覺化的方法來比較資料。 - 支援 Boost.Geometry 或 Boost.Polygon 這類的資料。
- 將 2D 幾何資料用畫出來觀察。
- Graphical Watch
- 以表格的形式,將多組變數用圖形的方式來個別表示。
- 支援 Boost.Geometry 或陣列。
- Plot Watch
- 把多組變數同時畫出來,進行觀察、比較。
其中,第一項 Debugger visualizers 在 VisualStudio 中並沒有額外的介面,但是後面三個,則是都有獨立的視窗介面,可以在 VIsualStudio 的「檢視」、「其他視窗」中找到。
下面就是官方提供的三個視窗的範例圖:
實際上,Geometry Watch 和 Plot Watch 的界面並沒有太大的不同,兩者都可以在同一個座標系統中顯示多組資料以進行比對,主要是針對呈現資料的性質有些差異。
而 Graphical Watch 在介面上就比較不一樣了,它可以同時顯示 Geometry Watch 和 Plot Watch 能顯示的資料,只是差別在於它是用表格的形式、一筆一筆資料會是獨立顯示的。
在支援的資料格式的部分,在網頁上算是有相當完整的列表。
基本上,他主要支援 Boost 和 STL 的資料,也支援 C-style 的陣列、或是陣列指標。
而在幾何的部分,主要就還是以 Boost.Geometry 和 Boost.Polygon 為主了;其他自訂型別、或是別的函式庫的資料要拿來用,可能會比較有難度。
由於 Heresy 沒有在使用 Boost.Geometry 和 Boost.Polygon,所以這邊 Heresy 在玩的時候,主要是以 Plot Watch 為主。
使用時,基本上就是在偵錯的時候,透過「檢視」、「其他視窗」裡的選項,來叫出「Plot Watch」的視窗。
右圖就是他的介面。上面是用來繪製資料的區域,下面則是顯示資料的列表。
要加入顯示的資料的話,基本上就是在下方表格的「Name」的欄位中,輸入變數的名稱;這樣他就會在後面顯示資料的類型、並自動賦予一個顏色。
而如果這組資料是他可以顯示的話,上面就會出現對應的圖形了。
右圖所呈現的資料有四組,其中 a 和 f1,5 是一維陣列、所以是以 bar chart 來顯示;v 和 f1,10;f2,10 則是代表二維陣列,是用一個點一個點來描繪的。
而這些資料的個別型態,可以參考下面的測試程式碼:
#include <map> #include <array> #include <vector> int main() { float* f1 = new float[10]{ 1,2,3,4,5,6,7,8,9,10 }; float* f2 = new float[10]{ 1,2,3,4,5,6,7,8,9,10 }; std::array<float, 10> a{ 10,9,8,7,6,5,4,3,2,1 }; std::vector<std::pair<float, float>> v; for (int i = 0; i < 50; ++i) { float f = 0.1f * i; v.push_back({ f, sin(f) }); } return 0; }
在這邊,a 是直接使用 std::array<>,應該沒什麼問題;其他像是 vector、list、deque 等,也都是支援的。
v 則是 std::vector<std::pair<float,float>> 來代表一連串的 2D 點;這邊之所以使用 std::pair<> 來代表單一點位,主要是因為 Graphical Debugging 能支援的點的類型,基本上只有下面這些:
- STL: complex, pair
- Boost.Geometry: point, point_xy
- Boost.Polygon: point_data
那其他的資料要怎麼畫呢?針對一般性的資料陣列,Graphical Debugging 可以透過簡單的語法,來進一步描述資料來做繪製。
以 f1,5 來說,f1 就是一個指到大小為 10 的浮點數陣列的指標;而在後面加上「,5」,就是告訴 Graphical Debugging 把它視為一個大小是 5 的陣列,也就是說拿他的前五個數字來做繪製。其結果就是一個 bar chart。
而 f1,10;f2,10 則是把 f1,10 和 f2,10 個別視為一個大小為 10 的陣列,然後把兩個放在一起、當作一個二微陣列來繪製;所以它的結果,就會類似 v,變成是以點組成的圖形。
透過這種直接去存取指標的方法,在某方面來說,應該也算是稍微增加了 Graphical Debugging 的使用彈性。
而同樣的資料,在 Geometry Watch、Graphical Watch 在 Plot Watch 中的話,他的呈現效果大概會是下面的樣子:
其中,由於 Geometry Watch 並不支援一維陣列的 bar chart,所以 a 是畫不出來。
另外,Plot Watch 因為不支援幾何圖形,所以如果有用到 Boost.Geometry 的話,那他也會畫不出來。
整體來說,個人覺得這個套件在某些情況下,應該算是滿實用的!由於是要針對計算的結果來找問題的時候,如果能把他們畫出來,有的時候是很方便的~
但是相對地,他的缺點是他主要支援 STL 和 Boost,而除了預設有支援的類別外,似乎並沒有提供比較大的客製化彈性;所以如果是使用自定義的型別的話,Graphical Debugging 似乎就完全沒用了…
最後,Graphical Debugging 和之前介紹過的「ImageWatch」有點類似,不過 ImageWatch 能呈現的主要是「圖片」,而 Graphical Debugging 則是把資料畫出來,其實在對應的資料的性質上還是不同的。