首页 > 代码库 > VC++6.0调试:Watch窗口的使用

VC++6.0调试:Watch窗口的使用

 1 #include <stdio.h> 2 #include <windows.h> 3  4 class AutoExpand 5 { 6 public: 7     AutoExpand(int val, char* pval) 8     { 9         a = val;10         p = pval;11     }12 private:13     int a;14     char *p;15 };16 class CantExpand17 {18 public:19     CantExpand(int val, char* pval)20     {21         a = val;22         p = pval;23     }24 private:25     int a;26     char *p;27 };28 29 int main(void)30 {31     int p[4] = {0x31,0x32,0x33,0x34};32     int *a  = p;33     34     FILE* fp = fopen("File Not Exist", "r");35     DWORD dwError = GetLastError();36     37     AutoExpand ae(10, "abc");38     CantExpand ce(10, "abc");39 40     return 0;41 }

      上面代码中出现的变量先说明一下:

  p: 是整形数组,含四个元素,总共16Byte;

  a: 整形指针,指向数组p;

  fp: 文件指针,用来标识打开的"File Not Exist",我机器里是没这个文件的;

  dwError: 获得fopen失败的错误码。一般来说可以用FormatMessge来格式化这个错误原因或者直接用VC自带的工具errorlookup来查找这个错误码的解释;

  ae和ce: 是自定义的AutoExpand类型的变量和CantExpand类型的变量。注意,这两种类型只有类型名字不同。

  下面看一下我在调试这个程序的时候,watch窗口的显示:

  

  上图中,左边是Context窗口的Locals页,显示所有局部变量。右边是Watch窗口,是我自己添加的要观察的对象。 

  好,先看看整形数组p。我们看到Context窗口的显示p其实只显示了数组的地址,点了+号展开后,显示出了4个整形数据。而右边窗口,我添加了一个p,c。p后面加个",c"是什么意思呢?看看效果,p,c下面的[0],[1],[2],[3]显示的是这4个整形值对应的ascii字符哈。所以从这里有了第一个小技巧:

  1.watch窗口中,在整形变量后面加上",c"可以显示该变量对应的ASCII字符。实际上,可以直接敲数字这么显示也行。比如上面右边窗口中的118,c的对应值是‘v‘。也就是说118对应的ASCII字符是‘v‘。那么,反过来,要知道一个字符的ASCII码值怎么看呢?看上面,‘v‘,d就是显示字符‘v‘对应的十进制ASCII码值是118。 ‘v‘,x显示的是对应的十六进制的ASCII码值。除了",c"   ",d"   ",x"外,还有一些其他的参数可以加,见后面的附表。

  然后我们看看变量a。a是个指针。看左边窗口,即使点了它的+号展开,也只看到了它指向的地址的第一个元素(49)。如果想要看得更多的数据,也可以像我一样,在上面的Memory窗口里看。但是Memory窗口只有一个,要看多个指针指向的数据就麻烦了,切来切去。那就在watch窗口中显示吧,a,4就可以了,看到我的watch窗口的显示没?所以,有了第二个小技巧:

  2.watch窗口中,把指针当成数组看,只要在指针名后面加上一个长度,就可以想看数组一样看到对应的数据了。比如我上面的a,4。那么如果一个指针指向的数据很大,比如一个整形指针a是指向一个1000个整数的大块内存,我只想看看最后4个数据,要怎样呢?那就(a+996),4 呗。从第996个数据开始,看4个~

  接下来这个小技巧是我最喜欢的一个了。调试中遇到系统函数调用失败的情况,通常都要加上GetLastError()函数获得返回值,然后查对应的解释才知道错误原因。比如,我上面的代码要打开一个不存在的文件,结果fopen失败。取回了错误码dwError=2,一查才知道是文件不存在。那么可不可以不用查,调试器直接告诉我原因呢?当然可以,不然我写这干嘛!刚才的错误码2是记录在dwError中了,所以只要在watch窗口看看dwError,hr看value栏:系统找不到指定的文件!爽吧!总结一下,第三个小技巧:

  3. 在watch窗口中察看错误原因,只需要在错误之后面颊上",hr"就可以了。比如我上面的 dwError,hr 和 2, hr 都能够显示错误消息。想看某个错误码的解释,只要后面加上",hr"就轻松搞定,非常方便!这里还要提一下的是,即使不调用GetLastError()也是可以看错误原因的。在fopen()调用完后,直接在watch窗口敲err,hr也可以显示最近一次的错误原因。但是我机器重新装了os,还没装vc,现在用的还是安装前的尸体。所以这个err,hr的显示有问题。不过还是有应对之法,那就是强大的TIB信息。watch窗口看看*(unsigned long*)(TIB+0x34), hr也是一样的。至于为什么吗,那就是GetLastError的机制了。

  还剩2个变量,ae和ce。这两变量类型名不同,但是其他全都一样。为什么这两个变量在watch窗口中显示的不一样呢?ae直接显示出了类成员的值,ce就显示了个......嗯,这就是最后一个小技巧:

  4. 在vc安装目录的msdev\bin目录下有个autoexp.dat文件。可以在里面自定义数据的显示。具体的看看它前面的大段说明,说得很详细。我就是在文件后面加上一行AutoExpand =int_val=<a,d> sz_val=<p,s>。

 

附表:

  下表说明调试器可识别的格式说明符。

 

说明符格式显示
d,isigned 十进制整数0xF000F065-268373915
uunsigned 十进制整数0x0065101
ounsigned 八进制整数0xF0650170145
x,X十六进制整数61541(十进制)0x0000F065
l,h用于 d、i、u、o、x、X 的 long 或 short 前缀00406042,hx0x0c22
fsigned 浮点型3./2.1.500000
esigned 科学计数法3./2.1.500000e+000
gsigned 浮点型或 signed 科学计数法,无论哪个都更短3./2.1.5
c单个字符0x0065101 ‘e‘
s字符串0x0012fde8"Hello world"
suUnicode 字符串 "Hello world"
hrHRESULT 或 Win32 错误代码。(调试器自动将 HRESULT 解码,因此这些情况下不需要该说明符。0x00000000LS_OK
wc窗口类标志。0x00000040WC_DEFAULTCHAR
wmWindows 消息数字0x0010WM_CLOSE

 

  下表包含用于内存位置的格式化符号。

符号格式显示
ma64 个 ASCII 字符0x0012ffac .4...0...".0W&.......1W&.0.:W..1...."..1.JO&.1.2.."..1...0y....1
m以十六进制表示的 16 个字节,后跟 16 个 ASCII 字符0x0012ffac B3 34 CB 00 84 30 94 80 FF 22 8A 30 57 26 00 00 .4...0...".0W&..
mb以十六进制表示的 16 个字节,后跟 16 个 ASCII 字符0x0012ffac B3 34 CB 00 84 30 94 80 FF 22 8A 30 57 26 00 00 .4...0...".0W&..
mw8 个字0x0012ffac 34B3 00CB 3084 8094 22FF 308A 2657 0000
md4 个双倍字长0x0012ffac 00CB34B3 80943084 308A22FF 00002657
mq2 个四倍字长0x0012ffac 7ffdf00000000000 5f441a790012fdd4
mu2 字节字符 (Unicode)0x0012fc60 8478 77f4 ffff ffff 0000 0000 0000 0000

  可以使用带有计算为位置的任何值或表达式的内存位置说明符。