当前位置:C++技术网 > 资讯 > 指针调试怪象分析和解决:无法查看指针指向变量的值

指针调试怪象分析和解决:无法查看指针指向变量的值

更新时间:2016-10-09 10:50:18浏览次数:1+次

    最近在做TCP通信的监控程序,也就是Socket通信。在接受到数据后,为了效率,就直接将指针传递给上层,然后上层逻辑就取出指针指向的内容进行判断分析和处理。
    所有的通信命令即协议里规定的一问一答式的命令,都是使用同一个缓冲区来接受数据的。整个通信基础使用的是完成端口,所有数据到来都是排队有序的向上传递,所以不会遗漏数据。所以,可以使用一个缓冲区一个个的来接受和处理数据。
    然而,如果出现了问题,那就要调试。调试的时候,将断点打在了处理命令的位置。然而,当运行到断点处时,也就是收到了对应的命令的时候,程序运行停下来了,并进入了调试状态。然而问题来了。当我将光标放在指针变量上面时,没有任何提示,不过其他局部变量是有提示的。在VS环境下,调试非常方便的,只要将光标放在断点处的变量上,就可以看到变量的值。此时却没有提示指针所指向的值。
    一开始,我以为是不是VS出现了Bug,或者是代码编译的不完整,所以重新生成了解决方案好几次,依然如此。如果说是Bug,那其他局部变量却可以提示值,也说不过去。
    经过一番思考,意识到了一个问题。对于指针,或多或少都有很多的敬畏,太强大以至于有时候容易hold不住。为了效率才让指针传递,其实这样做的时候,也是有些担心的。以前一个项目里,指针到处飞,最后导致经常程序崩溃,因为项目代码太多,而且是其他人写的,所以非常头疼。所以对于传递指针,需要非常慎重。当然,我这里倒不是出现了崩溃问题。只是调试的时候,没有和普通变量一样查看值。
    仔细分析了程序的流程,大致想到了原因。因为通信程序是一个独立的线程,这个线程在不停的接受命令,接收到的数据会向上传递。主线程进入调试状态,处于单步执行模式,而通信线程却属于独立自由运行状态,所以,数据照常向上传递,因此带来了问题。
    主线程进入调试状态,因为得到的是缓冲区的指针,而指针指向的缓冲区的内容,在命令到来的时候,被通信线程接收的数据覆盖了。一旦缓冲区被覆盖,VS是没有办法跟踪当前调试的指针的值应该是什么样的,或者说这个指针指向的缓冲区的内容是什么。因为内容被覆盖了,显示出来也是错误的,所以才出现了“无法查看指针指向变量的值”。
    这个问题属于典型的调试问题。对于没有碰见过的新手来说,就会觉得非常诡异。好在我之前调试过一个类似的代码,那是Windows界面程序的代码。Windows要对控件进行点击测试,然后返回测试的结果,表明你点中了什么位置。然而,当你进入调试的状态的时候,就干扰了正常的测试流程的进行,所以进入调试状态后,往往得不到正确的结果。
    虽然两种情况不一样,但是有共性。找到共性,我们可以提取出应对的办法,而不会是一筹莫展。而共性就在于,调试状态打乱了正常的执行流程,导致不可预测的结果。不要说调试不能正常的查看状态了,甚至执行的流程都不正确了,所以再怎么调试都不会有什么结果。给人的感觉就是,水中月镜中花,只能看,不能摸。一旦你触摸,就失去了原有的模样。
    那是不是就没有应对的办法了呢?当然不是!
    我们要调试,最基本的原则是不能干扰正常的执行流程,否则就没有任何意义了。所以,我们要保持正常的程序流程再来观察。既然直接打断点调试会影响程序的正常流程,导致怪异的调试现象和错误的流程,那么我们就不要让程序进入调试状态,而是以观察者的身份静观其变。可能你会说,不打断点,如何静观其变呢?
    在Linux程序调试时,用得最多的就是输出日志。我们就是在运行的位置,多加一些记录当前状态的日志代码,此时我们只是多执行了一句代码而已,并不会影响程序的正常的流程。而且,对于指针指向的缓冲区的数据,都可以打印出来观看。在不影响正常流程的情况下,我们也可以观察分析程序的运行状态。只不过,用日志形式调试比较麻烦,不过对于这样的情况,也只好这样了。
    Windows程序员不大习惯用日志来调试分析,不过,大部分情况不需要。在这样的特殊情况下,还是必须使用的。
    我们这里就是两个典型的案例需要用到日志来查看分析程序的执行状态,即传递指针时,缓冲区随时可能被覆盖内容和界面的点击测试状态会因为调试状态而使测试结果发生变化。当然,这里只是两个案例,应该还有很多场景差不多,可以举一反三。
    总之一句话,调试状态会引发程序流程改变的情况,不能直接打断点调试程序了,需要用日志形式来观察分析。