快捷搜索:

您的位置:澳门新葡4473网站 > 项目 > VC++6.0调试篇:变量的观察

VC++6.0调试篇:变量的观察

发布时间:2020-01-24 10:11编辑:项目浏览(123)

    写一下VC6的watch窗口的一些小技巧,对于调试过程是非常有帮助的。VC6年纪已经很大了,微软好像也不再支持,但是还是有很多人在用。我本人是非常喜欢它的小巧(相对vs2003,2005),占资源少,即使这样它的调试功能仍然超级强,真是不错。 

     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 CantExpand
    17 {
    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 }
    

           好,废话到此结束,下面贴代码来说明:

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

    #include <stdio.h>
    #include <windows.h>

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

    class AutoExpand
    {
    public:
        AutoExpand(int val, char* pval)
        {
            a = val;
            p = pval;
        }
    private:
        int a;
        char *p;
    };

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

    class CantExpand
    {
    public:
        CantExpand(int val, char* pval)
        {
            a = val;
            p = pval;
        }
    private:
        int a;
        char *p;
    };

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

    int main(void)
    {
        int p[4] = {0x31,0x32,0x33,0x34};
        int *a  = p;
        
        FILE* fp = fopen("File Not Exist", "r");
        DWORD dwError = GetLastError();
        
        AutoExpand ae(10, "abc");
        CantExpand ce(10, "abc");

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

        return 0;
    }

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

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

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

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

      图片 1

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

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

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

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

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

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

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

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

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

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

    图片 2

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

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

      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的机制了。

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

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

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

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

    然后我们看看变量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就显示了个......嗯,这就是最后一个小技巧:

    说明符 格式 显示
    d,i signed 十进制整数 0xF000F065 -268373915
    u unsigned 十进制整数 0x0065 101
    o unsigned 八进制整数 0xF065 0170145
    x,X 十六进制整数 61541(十进制) 0x0000F065
    l,h 用于 d、i、u、o、x、X 的 long 或 short 前缀 00406042,hx 0x0c22
    f signed 浮点型 3./2. 1.500000
    e signed 科学计数法 3./2. 1.500000e+000
    g signed 浮点型或 signed 科学计数法,无论哪个都更短 3./2. 1.5
    c 单个字符 0x0065 101 'e'
    s 字符串 0x0012fde8 "Hello world"
    su Unicode 字符串   "Hello world"
    hr HRESULT 或 Win32 错误代码。(调试器自动将 HRESULT 解码,因此这些情况下不需要该说明符。 0x00000000L S_OK
    wc 窗口类标志。 0x00000040 WC_DEFAULTCHAR
    wm Windows 消息数字 0x0010 WM_CLOSE

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

     

    附表:

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

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

    符号 格式 显示
    ma 64 个 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&..
    mw 8 个字 0x0012ffac 34B3 00CB 3084 8094 22FF 308A 2657 0000
    md 4 个双倍字长 0x0012ffac 00CB34B3 80943084 308A22FF 00002657
    mq 2 个四倍字长 0x0012ffac 7ffdf00000000000 5f441a790012fdd4
    mu 2 字节字符 (Unicode) 0x0012fc60 8478 77f4 ffff ffff 0000 0000 0000 0000
    说明符 格式 显示
    d,i signed 十进制整数 0xF000F065 -268373915
    u unsigned 十进制整数 0x0065 101
    o unsigned 八进制整数 0xF065 0170145
    x,X 十六进制整数 61541(十进制) 0x0000F065
    l,h 用于 d、i、u、o、x、X 的 long 或 short 前缀 00406042,hx 0x0c22
    f signed 浮点型 3./2. 1.500000
    e signed 科学计数法 3./2. 1.500000e+000
    g signed 浮点型或 signed 科学计数法,无论哪个都更短 3./2. 1.5
    c 单个字符 0x0065 101 'e'
    s 字符串 0x0012fde8 "Hello world"
    su Unicode 字符串   "Hello world"
    hr HRESULT 或 Win32 错误代码。(调试器自动将 HRESULT 解码,因此这些情况下不需要该说明符。 0x00000000L S_OK
    wc 窗口类标志。 0x00000040 WC_DEFAULTCHAR
    wm Windows 消息数字 0x0010 WM_CLOSE

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

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

    符号 格式 显示
    ma 64 个 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&..
    mw 8 个字 0x0012ffac 34B3 00CB 3084 8094 22FF 308A 2657 0000
    md 4 个双倍字长 0x0012ffac 00CB34B3 80943084 308A22FF 00002657
    mq 2 个四倍字长 0x0012ffac 7ffdf00000000000 5f441a790012fdd4
    mu 2 字节字符 (Unicode) 0x0012fc60 8478 77f4 ffff ffff 0000 0000 0000 0000

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

    本文由澳门新葡4473网站发布于项目,转载请注明出处:VC++6.0调试篇:变量的观察

    关键词:

上一篇:linux中权限问题

下一篇:没有了