精华内容
下载资源
问答
  • 调试程序,是软件开发过程中的一个必不可少的环节。这篇帖子,匠人试着来整理一下一些调试的技巧。 说到“技巧”,这个词自从被所长批臭之后,匠人就吓得不敢再提,生怕一不小心就暴露了思想的浅薄和眼光的局限,...
     
    

    转自:http://bbs.21ic.com/icview-128517-1-1.html

    一、前言

    调试程序,是软件开发过程中的一个必不可少的环节。这篇帖子,匠人试着来整理一下一些调试的技巧。
    说到“技巧”,这个词自从被所长批臭之后,匠人就吓得不敢再提,生怕一不小心就暴露了思想的浅薄和眼光的局限,呵呵。所以咱们不叫“技巧”,干脆低调点,就叫“雕虫小技”吧。
    这里所讨论的“调试”技巧,有些是必须结合开发工具本身的功能来实现,而有些可以通过烧录芯片来验证。
    各种开发工具,提供的功能多少强弱也不尽相同,这些方法也未必都能套用。仅供参考吧。
    最后说明一下,这是没有草稿的帖子,匠人仍然以不定期连载的方式,边写边发边改。可能结构会比较混乱。欢迎大家一起参与讨论。

    二、磨刀不误砍柴功

    在调试之前,需要掌握以下一些基本功:
    1、熟悉当前的开发(调试)环境,比如:设置断点、单步运行、全速运行、终止运行,查看RAM、查看堆栈、查看IO口状态……总之,要熟练掌握基本操作的方法,并深刻了解其中意义。
    2、了解芯片本身的资源和特性。
    3、了解一点汇编语言的知识。(本来匠人是准备写“精通”的,但考虑到现状,还是“放低”这方面的要求罢了)。
    4、掌握基本的电路知识和排错能力。(软件调试有时也会牵涉到硬件原因。总不能连三极管的好坏都不能识别吧?)
    5、万用表、示波器、信号发生器……这些工具总该会用吧?
    6、搜索、鉴别资料的能力。(内事问百度、外事问古狗、有事没事上21ic网)
    7、与人沟通,描述问题的能力。(调试36计的最后一计——就是向他人讨教。当然,你得把话说明白才行)
    差不多了,如果上述7把砍柴刀磨好了,就可以开始调试了。接下来,请调入你的程序……
    ——什么?你说你程序还没写?
    ——匠人倒塌……

    三、优先调试人机界面

    面对程序中的一大堆模块,无从下手是吗?好吧,匠人告诉你,先调显示模块,然后是键盘。
    为什么要先调显示模块?道理很简单,我们说“眼睛是心灵的窗户”,同样,“显示是程序的窗户”。一旦把显示模块调试好了,就可以通过这个窗口,偷 窥 (天呐,这两个居然是敏感字!) 程序内部的数据和状态了。
    然后紧接着,就是调试键盘模块。有了这个按键,我们就可以人工干预程序的运行了。
    ——什么,你的程序没有显示和按键?
    ——这位童鞋,你真不幸,请去检查一下自己的人品和星座运程先。谢谢。
    实在是没显示?再看看系统有蜂鸣器吗?如果侥幸有的话,也能凑合着发发提示声音吧?
    或者,有串口吗?可以考虑借助PC 端的串口调试软件来收发数据,这也是一个间接的人机交流方法。
    总而言之,要尽快建立人机交流界面。

    四、慢镜头的威力

    2009年春晚捧红了魔术师刘谦(这位老兄名“谦”,其实一点都不谦虚——长的帅不是错,出来拽就是罪过了!),也勾起了大家对魔术的浓厚兴趣,如何识破那些快速的眼花缭乱的魔术手法呢?很简单,用慢镜头回放即可。据说刘谦那个橡皮筋魔术的手法就是被人如此识破的。
    回到我们单片机上来。我们知道,单片机的运行速度,一般都是在几M到几十M(当然,也有为了节能而采用几十K的低速)。不管怎么样,这个速度都远远超出了我们人眼能够分辨的速度。眼睛一眨,也许几M条指令已经执行过去了。
    比如说数码管显示(假设有4位数码管)。平时我们看到数码管同时点亮着,但是实际上,这4个数码管是逐个扫描的。在任意一个时刻,只有一位数码管被点亮。在微观上,我们可以进一步把每位数码管的扫描动作细分为以下几个步骤:
    1、关闭上一位数码管的位选信号;
    2、输出当前位数码管的段选信号;
    3、开启当前位数码管的位选信号;
    4、启动1ms延时;
    5、延时结束后,指针移动到下一位数码管,并重复上述4个步骤,如此周而复始。
    你看,这样是不是就像用一个慢镜头在分解显示扫描的动作了?
    那么如何实现这个慢镜头呢?方法很多:
    1、单步运行(需要仿真器支持);
    2、在每一步分动作之后设立断点(需要仿真器支持);
    3、在每一步分动作之后插入足够的延时,让我们肉眼可以看清楚这些分动作(不需要仿真器,适合烧片测试);
    通过慢镜头的反复回放,我们就可以发现,到底是哪一个分动作出现了问题。
    这个技巧,不仅仅适用于调试显示程序,也适用于按键扫描或其它模块。只要一个功能可以被细分为若干的动作,那么这一招“慢镜头分解法”都是可以使用的。

    五、给程序安装个黑匣子

    某年某月的某一天,一架飞机以优美的抛物线形状,一头栽到海里去了……几天后,人们找到了飞机的黑匣子,里面记录了飞行员的最后一句话:“天呐,我看到火星人了!……”
    以上空难情节我们经常会通过新闻看到吧(当然,最后一句是匠人版的科幻情节)。看看,飞机的黑匣子可以记录并再现现场,多么神奇!欧耶!
    我们在调试程序时,也可以借鉴这个方法,给程序按装一个黑匣子。程序中的黑匣子其实就是一个在内存中开辟的队列。队列的原理我们很清楚,先进先出,后进后出(与飞机黑匣子的特性相同)。
    比如说吧,假设我们的系统在工作中,某个输入量的采样值经常受到不明原因的扰动。我们要摸清这种扰动的规律,以便对症下药。但是这种扰动稍纵即逝。
    我们的困扰是:程序正常运行时看不出规律,单步走又难以捕捉扰动。怎么办?
    有没有办法,把扰动记录下来?
    当然可以。
    我们可以利用系统里剩余的RAM,开辟一块单元,做成队列。并写段测试程序,定时把新采样值压入队列。
    然后我们让程序运行,在需要的(任意)时刻,让程序停下来。这时,队列里记录的就是最新一批采样数据。
    只要队列的深度足够大,我们就可以找出扰动的规律来。
    ——什么,你问我什么叫队列?
    ——匠人曰“天呐,我看到火星人了!……”

    六、在程序中设卡伏击,拦截流窜犯

    警察抓流窜犯的场面我们都很熟悉了。一般的方法,就是以案发现场为中心,在犯罪分子逃窜的必经路口,设卡盘查。有道是天网恢恢疏而不漏,叫你插翅也飞不过去。
    有时,程序中也会出现这样一个“流窜犯”,它就是PC指针。
    对于一个未经调试的不成熟的程序来说,导致PC指针跑飞的因素很多,我们逐条列举并分析之:
    1、电磁干扰(如果不是在现场,那么这一条可以暂时不考虑。因为在调试环境下一般不会有干扰);
    2、程序结构错乱(喜欢用jmp或goto类指令的尤其要注意这点);
    3、堆栈溢出或错乱,导致PC指针出错;
    4、PC指针被错误改写(有些芯片PC指针存储单元和其它RAM单元的访问方法是一样的,很容易被误写);
    5、数据错误,导致程序没有按照预期路径运行;
    6、看门狗溢出(原因一般是因为看门狗设置不当、喂狗不及时、程序堵塞或者程序死循环);
    7、中断被意外触发;
    8、外部电路问题,比如电源不稳等等;
    9、其它……
    当我们开始怀疑PC指针时,我们首先要做的是确认PC指针是否跑飞了,其次要找到PC指针跑飞的证据。
    我们可以在不同的分支路口,或者在我们怀疑的地方,设立断点,看程序是否走了不该经过的路径。
    举个例子,比如我们怀疑程序运行中看门狗发生了溢出复位,那么很简单,我们只需要在初始化入口设立一个断点,让程序运行。正常情况下,程序只会经过一次该断点。如果再次经过该断点被拦截,那么我们就可以初步确诊“看门狗发生了溢出复位”。
    再举个例子,比如程序中某个环节有A、B两个分支,正常时只走A分支,不正常时才走B分支。那么我们可以在B分支设立断点,程序一旦异常,走入B分支,就可以被拦截下来。
    程序被拦截下来后,我们可以勘察现场,查看RAM区内容和程序刚走过的路径,从中分析导致程序PC指针错乱的原因。
    当然,并不是每一次伏击守候都能一举擒获流窜犯(敌人是“狡猾”的,呵呵)。这就需要我们多一份耐心和技巧。通过不断调整断点位置来改变拦截地点。逐渐逼近并找到根源(流窜犯的老巢),然后一举拿下。

    七、向猎人学习挖坑设陷阱的技术

    上一回说到,在程序中设卡(断点),可以拦截流窜犯(程序流程错误)。实际上,断点的功能可强大了,不但可以拦截程序流程错误,也可以拦截数据错误。当然,这需要一些辅助手段。
    还是以前面提到的一个例子来说。比如某个采样值(当然,也不一定是采样值,在这里也可以是RAM中任意单元中的值)受到未明因素影响,经常“乱跳”。这种数据出错的原因,可能如下:
    1、计算错误(比如溢出),导致结果出错;
    2、被其它程序段误改写;
    3、其它原因……
    当数据出错后,我们希望能够在最快时间内,让程序停下来,这样才能有效查出是哪一段程序出了问题。
    有些调试环境本身可以捕捉数据错误,并产生断点中断。这当然最好不过。但是如果调试环境本身不提供这种捕捉功能,那么就需要我们自己来制造机关了。
    看看猎人是是如何做的:他们会在猎物经过的地方,挖个坑,上面盖上浮土。当小型动物经过时,浮土不会塌陷。而当体重较大的动物经过时,它们的体重就会压垮浮土,掉进猎人的陷阱。
    猎人的这个陷阱机关,妙就妙在是它“智能”的,会根据动物的体重进行筛选。
    轻巧的小白兔来了——放过,笨重的大狗熊来了——捕获!欧耶!
    好了,回到程序中来,假设我们要监控的那个RAM单元,正常值域为0~9;那么我们可以写一段测试代码,判断数值是否>9,根据判断结果执行两个分支,并在那条错误的分支路径上设置断点。
    如果数据没有出错,程序会一直运行(小白兔请放心过去);直到数据错误发生,断点会自动停下来(大狗熊给我拿下)。
    我们可以把这段测试程序,插入在“狗熊出没”的地方,“守株待兔”(其实“守坑待熊”)。
    接下来的事情,就跟上回说的抓流窜犯原理差不多了。
    ——什么,你喜欢吃兔肉?不喜欢吃熊掌?
    ——你也太没有爱心了,唉。。。。。

    八、在程序中设置窃 听 器

    1、你的定时中断频率是否等于设想的那个值?
    2、你的主程序循环一次花了多少时间?
    3、你的程序中某一次复杂计算需要耗费多少时间?
    4、你的程序里某个动作发生的具体时刻是什么时候?
    5、……
    ——也许你不关心这些时间,那么你就不必看这一回了。
    但是——
    1、当我们的计时时钟发生偏差时,我们希望知道定时中断是否正常发生了;
    2、当我们的程序任务较多,并已经导致任务堵塞时,我们需要知道主程序运行一圈的时间是多少,以便我们合理分割任务,避免堵塞;
    3、同样,为了避免任务堵塞,我们要了解那些复杂计算所消耗的时间,并采取必要的措施(优化算法、分时间片执行、调整执行频率)来保证系统的实时性;
    4、当程序中某些动作与其它动作或状态存在时间上的关联时,我们必须严格控制它的执行时机,确保它在正确的时刻被执行到;
    5、……
    我们如何才能从外部,对这些这些发生在程序内部的时间(时刻)进行精准的测量?
    我们当然不能钻到芯片里面去监视每一条指令的运行情况。但是,我们可以学习一下克格勃,给程序安装个窃  听 器。
    具体方法:
    1、首先,你需要一台示波器。没有的话,可以去偷、去抢、去骗。总之,最终你搞定了这台示波器,欧耶。
    2、其次,你的芯片上要有一个空余的输出口用作测试口。没有的话,就拆东墙补西墙吧,先把不相关功能的IO口挪用一下啦。总之,最终你搞定了这个测试口,欧耶。
    3、接下来,你可以在你要“监听”的程序段中,写一小段程序,对那个测试口取反(或者输出一个脉冲)。
    4、最后让程序全速运行起来,你就可以用示波器来监听程序的运行状况了。
    以本回开始举的几个例子来分析:
    1、如果要测试定时中断频率,只要在中断中对这个测试口取反,即可通过示波器观测中断频率;
    2、如果要测试主程序运行周期,只要把取反指令放在主程序循环圈中,即可;
    3、如果要测试一次复杂计算(或其它动作)需要消耗多少时间,我们只需在计算之前把测试口变为高电平,等到计算结束后立即把输出口恢复到低电平,这段高电平的时间长度,即为计算消耗时间;
    4、如果想知道两个动作之间的延时时间,我们也可以按照上一条方法一样,在两个动作发生前把测试口分别取一次反。就可以通过示波器轻松测试出来。
    5、根据实际案例的具体情况,我们可以把这种窃听技术变换出更多花样。比如我们可以用两个IO口做测试口,同步检测两个事件的发生时刻,并测量其相互时间关系。等等……
    6、引申开去,这个测试口不仅仅可以检测时间,也可以用来检测内部数据的变化。比如当某个数据的值发生“越界”时,输出一个高电平(平时为低电平)。
    等到我们取得我们想要的测试数据,我们可以把这个临时的测试口功能撤销。同时,那些测试代码也可一并删除或屏蔽。
    总结:把程序内在的、不直观的、快速的一些状态变化,通过IO口传递出来,以便我们观测。——这就是我们这一回所讲的“窃 听 器”调试技巧的精髓。
    ——警告,请勿把“窃  听 器”安装在女生宿舍哦!
    ——那样的话,匠人岂不就成为教唆犯了。罪过,罪过。。。。。

    九、快镜头加速

    前面已经讲过慢镜头,这回再讲快镜头。
    慢镜头的作用的把程序的运行节奏降低,以便我们能够“一帧一帧”地观测程序的运行状态。而快镜头的作用,则相反,就是让程序的运行节奏变快,让我们验证一些原本需要消耗较多等待时间的功能。
    比如说,一个定时功能,定时范围是可调的,为1~24小时。如果我们要去验证,总不能傻等1~24小时吧?
    怎么办呢?快镜头来了。
    我们知道程序中的时间,是靠一级一级的计时器累计上来的。比如一个程序中分别有“时、分、秒”三个计时器单元。依次计数,逢60进一。“秒”计满60次了,则“分”+1;“分”计满60次了,则“时”+1;“时”计数超过设定值了,我们就可以判定定时结束。
    那么我们只要修改一下“分”到“时”的进位关系。比如改成:“分”+1;“分”计满1次(原本是60次)了,则“时”+1。这样一来,整个定时系统速度就比原来提高60倍。测试起来就很省时间了。
    当然,测试完成后,记得要把刚才做的测试代码改回原样哦。
    举一反三,“快镜头”技巧,不仅仅用在定时方面,也可以用在计数方面。通过对数据的变化“加速”,来加快我们的测试速度。
    ——什么,你喜欢磨洋工,愿意花24小时去测试那个定时功能?
    ——哈哈,放心,我不会告诉你的老板的——除非他使出美人计来对付我。欧耶!

    十、拉闸睡觉!统一管理调试代码

    前面介绍的几种方法,需要在程序中增加一些临时性的调试代码。
    有些调试代码是无害的,比如只是一些延时指令,或者是在不使用的IO口上有一些输出而已。
    但另一些调试代码,与正式要求的程序功能是相冲突的。那么这些代码在完成调试之后就应该被删除或屏蔽掉。
    那么会不会出现意外,把本该被删除的代码漏删了?结果埋下祸害?——如果调试代码少,出错的概率比较低,只要认真仔细点还好办;但是如果程序中的调试代码写得比较多,那么确实很担心会发生这种问题。
    或者另一种情况,就是前脚把调试代码删除或屏蔽掉,后脚发现还需要再调试,又要重新输入或打开那些代码?
    如何管理这些代码呢?这个我们要向宿舍管理员学习了。他们是这么做的,给所有房间安装一个总电闸。到了晚上11点就把总闸一拉,看书的、打牌的、喝酒的、胡侃的、泡妞的、夜游的、Y们都给我老老实实睡觉去吧!
    程序中,这样的总闸也是可以通过条件编译的方式来实现的。就像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //#define TEST_MD        //调试状态标志(在调试时打开,正式烧录芯片时屏蔽)
        //在编写调试代码时,采用下面的形式:
        #ifdef TEST_MD                //如果是调试状态,则编译这段代码
                ……
                ……
        #else                        //如果不是调试状态,则编译这段代码
                ……
                ……
        #endif

    一个总闸,把管理简单化了。欧耶!

    十一、删繁就简,从最小系统开始!

    这篇手记写到上一节,原本已经结束了,直到今天看到网友问的一个问题:“我的程序调试都通过啦,为什么烧片后没有反应?”
    匠人突然发现,这篇手记的一个缺陷,就是过于集中讨论了调试中的软件技巧,却疏忽了硬件方面的问题。所以特意补充这个小节的内容:
    当你辛辛苦苦在仿真上完成了所有调试工作,却发现烧片后系统不工作,该怎么办?
    到 百脑汇去看看电脑修理工是怎么干活的:面对一台故障不明的电脑,修理工会把先不相关的部件拆掉,只留下电源、主板、CPU三样基本核心部件,看能否启动; 如果这一步通过了,他们会继续加上内存、显卡、显示器,看能否点亮;如果点亮了,接下来再加上:硬盘、键盘;最后才是鼠标、光驱、网卡、打印机、摄像头之 类。
    从最小系统开始,有条不紊地排查。这就是有经验的修理工们惯用的“最小系统法”!
    所谓的最小系统法,是指构建一个可运行的系统,必不可少的、最基本的硬件和软件环境。而在这里,我们特指硬件方面。
    如果要让一个单片机系统正常工作起来,需要哪些硬件条件,我们罗列一下:
    1、电源
    2、复位信号
    3、晶振信号
    Ok!无需多说了,这就是我们要优先排查的目标(也许你需要一个示波器!)。暂时忽视那些不相关的硬件。等单片机能够正常运行了,再去检查其它外围功能电路吧。
    如果上述3个方面都排查无误,系统还不能工作,那就是人品问题啦。赶紧找个牧师去忏悔,或者到百脑汇去帮老板干几天活。完了再回来继续查自己的板子上有没有短路、开路等弱智问题。
    最后再引申一下:在软件调试时,最小系统法也同样可以使用。先写一个只有最少的代码的系统,让程序跑起来,然后把模块一个个加入调试,不失为一种明智的方法。

    展开全文
  • TLD算法matlab版本的程序调试过程

    千次阅读 2012-12-15 16:06:43
    kalal的混合编程的代码很早就下载了,但是一直没有去调试,前一段时间看了差不多一个月的文献,终于把作者的算法大致讲的意思给弄明白了,但是里面涉及到的很多细节的东西还是不太清楚,由于自己刚换的方向,理论...

           kalal的混合编程的代码很早就下载了,但是一直没有去调试,前一段时间看了差不多一个月的文献,终于把作者的算法大致讲的意思给弄明白了,但是里面涉及到的很多细节的东西还是不太清楚,由于自己刚换的方向,理论基础薄弱,讲报告的时候,面对师兄的提问回答的不够好,结果被老师给批评了。做完报告便开始了作者代码的调试,由于前期问过很多的前辈这个代码改怎么调,但是大家似乎说的我还是不明白,没办法,还是得自己摸索。

           最开始调试的时候用的是我的64bit的系统,matlab2010a 64bit和vs2008 32bit,结果肯定是没调试出来的,各种错误。最后就开始换编译环境了,将vs2008换成vs201032bit,调试了好久,最后出现的错误,实在是不知道怎么改了,在网上搜了搜,发现好像还是说的是软件的bit问题,于是开始仔细的看作者的调试环境要求。作者的要求是三种环境,一种32bit的系统,一种64bit的系统,一种是在64bit的系统下面采取了一种折中的方式,就是在32bit的matlab2010a中安装一个补丁,以便和vs2010 的32bit软件配合使用,那么这样的话,电脑的系统虽然是64bit的,但是实际我们却把它转换成了32bit的方式,从而大大简化了调试的复杂程度。单纯的64bit调试方式要用cmake等等各种配置。

       环境配置好之后,首先在matlab中选择编译器,输入命令 mex -setup,调用vs2010的编译器,之后,在comile.m中将mex的地址转换为文件mex在电脑中的具体地址,然后将opencv的配置目录根据电脑中的opencv位置进行设置,配置之后大致上完成了,期间,要注意配置中的格式问题,例如,空格,反斜杠等等吧

    展开全文
  • VC程序调试

    千次阅读 2009-11-11 12:40:00
    一、VC程序调试方法VC的调试功能:首先,再次强调要用Go命令运行一个将要调试的程序;如果要中止调试状态下的运行程序可以点击Stop Debugging命令,还可以通过Break选项以可恢复方式中断调试程序的运行流程(用...

     

     调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言。不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件。

    一、VC程序调试方法

    VC的调试功能:首先,再次强调要用Go命令运行一个将要调试的程序;如果要中止调试状态下的运行程序可以点击Stop Debugging命令,还可以通过Break选项以可恢复方式中断调试程序的运行流程(用Restart选项可以重新开始运行程序);Step Into选项表示每次只执行一行语句(单步执行),但如果当前代码是调用一个函数,那么Step Into表示进入该函数,全部函数语句执行完后返回,而Step Over则是跳出这个函数;Step To Cursor选项表示程序将执行到光标所在的可执行语句行上;在调试多线程程序时,可以在线程函数或主应用程序线程中设置断点,还可以用Break选项结束线程后用Threads选项查看运行线程列表,也可以选择悬挂和恢复每个线程;在设置断点后,在VC "查看"菜单的"调试窗口"中可以查看变量、内存、调用堆栈、寄存器以及反汇编语句。在程序中设置断点的方法是,点击要设置的代码行并点击设置代码的工具栏按钮,会出现在代码行最左边的一个小黑点即是断点标志,这时再选Go程序会在执行到端点处停下来,如果要继续执行可以再选Go
      通过选择VC"工具"菜单下的"源浏览器"可以生成一个.BSC文件,使用浏览器可以从中发现多种信息:程序中任何一个变量、函数、类或宏在何处定义及引用;可以列出所有声明的函数类、变量、宏;可以发现调用一个指定函数的所有函数;可以找到一个指定类的派生来源或者它派生出哪些类。

    在使用微软程序开发库MSDN时,我们会发现其中的VC示例经常采用看似多余的ASSERT语句,其作用就是使程序具有"维护"性。对于Debug版本的VC程序,在遇到布尔值为FALSEASSERT语句处停止,并显示Assertion Failed对话;如果设置为发布版,所有ASSERT语句都会被预处理程序删除。ASSERT宏在发行版本中不起作用,而应该用VERIFY来进行发行版的调试。如果发行版本运行有问题,可以先禁止所有代码优化再进行调试。

    系统提供一系列特殊的函数或者宏来处理Debug版本相关的信息,如下:

    宏名/函数名

    说明

    TRACE

     使用方法和printf完全一致,他在output框中输出调试信息

    ASSERT

    它接收一个表达式,如果这个表达式为TRUE,则无动作,否则中断当前程序执行。对于系统中出现这个宏 导致的中断,应该认为你的函数调用未能满足系统的调用此函数的前提条件。例如,对于一个还没有创建的窗口调用SetWindowText等。 

    VERIFY

    ASSERT功能类似,所不同的是,在Release版本中,ASSERT不计算输入的表达式的值,而VERIFY计算表达式的值。


      在安装好VC系统之后,在VC之外的程序组中有一个程序Tracer是一个跟踪工具,在激活它后使用Go运行VC代码,在输出窗口就能够看到程序运行过程中的内部过程,包括DLL调用等,你如果看不到任何输出,可以转到菜单"查看"View)点击"输出"Output)。

      其实,MFC自身就提供有错误查找和TRACE语句,而TRACE语句的语法与printf非常类似,所以我们可以在程序中直接加入这条跟踪命令,如下所示:

    // Example for TRACE
    int i = 1;
    char sz[] = "one";
    TRACE( "Integer = %d, String = %s/n", i, sz );
    // Output: 'Integer = 1, String = one'


      在Developer Studio中还提供了一个ERRLOOK工具,程序员只要输入错误号就能得到系统出错信息或模块错误内容。

      MFCCobject派生的每个类都包含一个Dump函数,该函数可把当前状态转储(Dumping)到输出窗口,这在某些调试过程中会有用,以下代码是Dump函数的用法:

    // Example for CObject::Dump
    void CAge::Dump( CDumpContext &dc ) const
    {
     
    CObject::Dump( dc );
     
    dc << "Age = " << m_years;
    }


      在MFC中还有一个非常有用的类是CMemoryState,我们可以在程序的任何部分使用这个类检测内存冲突,并得到内存冲突的确切位置。CMemoryState类有3个成员函数:CheckPoint可将堆的当前状态存入类的实体;Difference可以比较两个实体包含的堆之间的差异;DumpStatistics用于标准化转储所有被CheckPoint捕获后分配到堆的对象,如CheckPoint未被调用实体未被初始化时,该函数将转储当前堆的所有内容。以下代码表示了CMemoryState类的使用方法:

    // Example for CMemoryState::CMemoryState
    // Includes all CMemoryState functions
    CMemoryState msOld, msNew, msDif;
    msOld.Checkpoint();
    CAge* page1 = new CAge( 21 );
    CAge* page2 = new CAge( 22 );
    msOld.DumpAllObjectsSince();
    msNew.Checkpoint();
    msDif.Difference( msOld, msNew );
    msDif.DumpStatistics();


      代码运行的结果为:

    Dumping objects ->
    {2} a CObject at $190A
    {1} a CObject at $18EA
    Object dump complete.
    0 bytes in 0 Free Blocks
    8 bytes in 2 Object Blocks
    0 bytes in 0 Non-Object Blocks
    Largest number used: 8 bytes
    Total allocations: 8 bytes


      在MFC类和VC中本身就有"异常情况"这个概念,并在此基础上形成它们处理系统错误和意外的主要机制。比如当系统内存分配殆尽时,你的运行程序就会收到内存异常的消息。这样就给了程序员消除异常的机会。

      MFC中的异常情况主要有:CArchiveException表示档案文件载入或保存时出错,CDBException属于数据库错误,CFileException为文件错误,CMemoryException为调用new时发生分配错误,CNotSupportedException表示指定操作不被支持,COleException表示在调用OLE操作时出错,COleDispatchException表示在OLE自动操作时出错,CResourceException表示资源找不到或无法创建,CUserException用于通知用户错误。
      MFC还包含一系列以Afx-为词头的调试函数:AfxAbort可以在发生致命错误时异常终止程序,AfxCheckMemory可以检查堆和剩余缓冲池的受损部分;AfxDoForAllClasses重声明所有CObject的派生类;AfxDoForAllObject重声明堆上所有CObject派生的对象;AfxEnableMemoryTracking启用或禁止内存追踪;AfxIsMemoryBlock用于确认指针所指内存有效;AfxIsValidAddress用于确认地址是驻留在程序的内存区域内;AfxIsValidString用于确认地址所指字符串有效;AfxSetAllocHook用于内存分配前进行检测;AfxTraceEnabled启动或禁止输出跟踪,AfxTraceFlags则进一步定制跟踪特征。

     

    二、VC6.0VC2008 Release版本调试参数设置比较

    VC6.0Release版本调试参数设置

    VC2008 Release版本调试参数设置

     

     

    三、注意细节

    1、对于所有有返回值的函数,都应该检查返回值,除非你确信这个函数调用绝对不会出错,或者不关心它是否出错。

    一些函数返回错误,需要用其他函数获得错误的具体信息。例如accept返回INVALID_SOCKET表示accept失败,为了查明具体的失败原因,应该立刻用WSAGetLastError获得错误码,并针对性的解决问题。

    2、有些函数通过异常机制抛出错误,应该用TRY-CATCH语句/TRY-CATCH-finally来检查错误 。程序员对于能处理的错误,应该自己在底层处理,对于不能处理的,应该报告给用户让他们决定怎么处理。如果程序出了异常,却不对返回值和其他机制返回的错误信息进行判断,只能是加大了找错误的难度。

    3VC中要编制程序不应该一开始就写cpp/h文件,而应该首先创建一个合适的工程。因为只有这样,VC才能选择合适的编译、连接 选项。对于加入到工程中的cpp文件,应该检查是否在第一行显式的包含stdafx.h头文件,这是Microsoft Visual Studio为了加快编译速度而设置的预编译头文件。在这个#include "stdafx.h"行前面的所有代码将被忽略,所以其他头文件应该在这一行后面被包含。

    对于.c文件,由于不能包含stdafx.h,因此可以通过Project settings把它的预编译头设置为“不使用”,方法是:

    弹出Project settings对话框

    选择C/C++

    Category选择Precompilation Header 选择不使用预编译头。

    4GetLastError来检测返回值,通过得到错误代码来分析错误原因

    5把错误信息记录到文件中

    6查看API的错误码,在watch窗口输入@err可以查看或者@err,hr,其中”,hr”表示错误码的说明。

    7、查看数组中的值时,在watch窗口输入数组名称,数组大小就可以查看里面的内容值。

    8Set Next Statement:该功能可以直接跳转到指定的代码行执行,一般用来测试异常处理的代码。

    9、使用映射文件调试

    a)、创建映射文件:Project settingslink项,选中Generate mapfile,输出程序代码地址:/MAPINFO: LINES,得到引出序号:/MAPINFO: EXPORTS

    b)、程序发布时,应该把所有模块的映射文件都存档。

    c)、查看映射文件:见通过崩溃地址找出源代码的出错行文件。

     

    展开全文
  • MFC中调试过程中查看printf输出信息

    千次阅读 2017-04-18 14:27:20
    在调试MFC程序时,我们经常需要查看特定位置变量的输出值。或者某特定条件执行时,给出一个输出标识。 一般来说,有3种方法: 1) 调用TRACE(LPCTSTR lpszFormat, ...)函数  MFC使用TRACE函数来打印...

    在调试MFC程序时,我们经常需要查看特定位置变量的输出值。或者在某特定条件执行时,给出一个输出标识。

    一般来说,有3种方法:

    1) 调用TRACE(LPCTSTR lpszFormat, ...)函数

        在MFC中使用TRACE函数来打印输出结果却是非常方便,和在控制台程序中使用printf函数的使用方法和效果类似。不过有几点  

        需要注意:一,TRACE函数的输出是在Output窗口的Debug选项下; 二,只有在DEBUG版本调试时才会有输出,如果是在

        Release版本调试或者运行程序时,将不会看到输出。

    2)使用AfxMessageBox( )函数来输出信息

         这个函数在调试时也比较常用,使用方法简单,此处就不做介绍。

    3)将标准输出定向到自己创建的控制台

          #include "io.h"
          #include "fcntl.h"

            void InitConsole()
          {
                int nRet= 0;
               FILE* fp;
               AllocConsole();
               nRet= _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
               fp = _fdopen(nRet, "w");
              *stdout = *fp;
              setvbuf(stdout, NULL, _IONBF, 0);
        }

      将此函数在MFC程序初始化的地方调用,即可使用控制台查看printf函数的打印信息

    原文:http://blog.csdn.net/brucezong/article/details/6889974

    展开全文
  • 程序调试记录

    千次阅读 2016-10-29 19:33:57
    最近把师兄的程序在万兆网络上进行测试,现在把调试中出现的问题进行记录: 1)其中一共是十六块板子,板子的配置文件是sipixel.xml,每块板子的配置信息里都有对应的IP,其中的IP即表示对读取板子的Server的IP信息...
  • Qt——程序调试

    万次阅读 2018-01-31 11:37:48
     传统的调试方法是设置断点进行调试,设置好断点后,按下F5或者左下角的调试按钮开始调试,这时程序先进行构建再进入调试模式。其中界面上有些按钮,例如继续按钮、停止调试按钮、单步跳过按钮、单步进入按钮、单步...
  • 第一部分调试策略 第1章调试的过程  虽然可能存在无数种错误,与此对应,潜在的也存在无数种调试策略,...像Elisabeth Kuble-Ross她的书《On Death and Dying》提到的悲哀五步曲那样,低效率调试过程的五步曲
  • MFC中调试过程中查看输出信息

    千次阅读 2011-10-20 11:49:13
    在调试MFC程序时,我们经常需要查看特定位置变量的输出值。或者某特定条件执行时,给出一个输出标识。 一般来说,有3种方法: 1) 调用TRACE(LPCTSTR lpszFormat, ...)函数  MFC使用TRACE函数来打印输出结果...
  • 1. import pdb import pdb 2. 运行的代码前加入 pdb.set_trace() 3. 运行单元格 然后弹出如下窗口: 4. 先教所有指令的爸爸:h/help ...英文自个儿琢磨吧,下面是一些调试过程中常用的指令 指...
  • Keil 程序调试窗口

    万次阅读 2017-03-27 20:21:14
    一、程序调试时的常用窗口 Keil 软件调试程序时提供了多个窗口,主要包括输出窗口(Output Windows)、观察 窗口(Watch&Call Statck Windows)、存储器窗口(Memory Window)、反汇编窗口(Dissambly Window...
  • 程序调试的一般思路

    千次阅读 2016-02-21 21:38:14
    本人在调试过程中总结了几点调试程序的一般方法,写出来和大家分享,能力有限,欢迎各位大神批评指正! 1.单步调试 从问题程序的起点开始,单步执行程序观察变量的变化过程,是最基本的程序调试方法。这种方法适合...
  • VC++程序调试

    千次阅读 2009-12-27 22:27:00
    csdn 发布者:admin 时间:2009-07-07 10:45:35 点击:713 1 前言 当程序的运行结果与程序员预想的不一样,如死机,计算值不正确,出现内存访问冲突等,就需要进行调试2 进行调试前的准备工作 因为程序调试是...
  • Android eclipse 程序调试

    千次阅读 多人点赞 2013-03-20 16:00:35
    用eclipse开发android程序的时,跟VS一样是可以断点单步调试的. 步骤如下. 1 设置断点:编码窗体的左边框上用鼠标双击,或者右键点击菜单,选择 Toggle Breakpoint菜单项即可. 2 debug模式下...
  • revit二次开发之程序调试

    千次阅读 2019-07-12 16:49:42
    小伙伴们revit二次开发时,需要对程序进行调试,小伙伴经常会出现以下问题 打了断点,但是程序不经过那儿 即使打了断点,程序也照常运行 … 其实出现这些问题,就是调试没有设置好。这里骑士小哥,手把手教小...
  • 逮虾户!Android程序调试竟简单如斯

    千次阅读 2019-03-07 10:40:32
    当然本节讨论的不是开车,而是Android开发老生常谈的程序调试。 一个开发仔的日常离不开:写BUG和解BUG,特别是多人协作的时候, 帮别人擦屁股(解Bug)的情况屡见不鲜。另外,接盘别人的项目,着手解 ...
  • QEMU中调试ARM程序

    千次阅读 2010-10-27 09:06:00
    我想用gdbserver来QEMU运行一个程序,然后用TCP链接将其连接到运行我PC上的GDB实例。gdbserver是一个软件层,它实现了GDB 的一部分功能(调试残桩),并提供了通过网络(或者串口)连接一个完整的
  • gdb调试过程中修改变量的值

    万次阅读 2013-10-16 18:31:41
     一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地GDB更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行...
  • MSP430的RAM中调试程序的研究

    千次阅读 2016-12-25 19:07:07
    Cortex-M3RAM中调试的文章百度有很多,但是和MSP430RAM中调试程序有关的文章却没有多少,百度只有一两个和RAM及MSP430有关的,但却不是RAM调试,而是重定位中断向量表到RAM及拷贝FLASH程序到RAM运行,于是...
  • GDB程序调试工具参考知识

    千次阅读 2016-04-01 18:38:08
    GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的...
  • Android程序调试方法介绍

    万次阅读 多人点赞 2019-02-20 19:47:14
    静态调试 适用于:通过打印变量的值来查看某一时刻值是否正确 Toast(Snackbar)打印法 一般的Android开发人员最爱的调试法,使用简便,仅需...方便是挺方便的,不过有一点要注意:Android 5.0后,如果把「消息通知...
  • gdb+gdbserver 方式进行ARM 程序调试

    千次阅读 2012-03-02 16:49:30
    gdb+gdbserver 方式进行ARM 程序调试 1: gdb 的简单使用 GDB 是GNU 开源组织发布的一个强大的UNIX 下的程序调试工具。或许, 各位比较喜欢那 种图形界面方式的, 像VC、BCB 等IDE 的调试, 但如果你是UNIX 平台...
  • linux驱动程序调试方法

    千次阅读 2018-07-09 21:13:51
    来自:...本文目的就是介绍驱动开发常用的几种直接和间接的调试手段,它们是:利用printk查看OOP消息利用strace利用内核内置的hack...
  • Android系统调试程序崩溃调试

    千次阅读 2017-09-01 14:50:51
    Android系统调试-Native 调试Android系统对于Native(C/C++)应用程序...但是Android系统的天然不支持这种调试方式,其内核就没有启用coredump生成机制,那么Android系统下我们使用什么方式调试Native程序的崩溃问题
  • ccs调试过程中碰到的问题总结

    千次阅读 2016-09-18 13:30:28
    //***********************************************************************************************************************************// 更新时间 : 2016/9/18 使用平台 : f8377d ...问题描述 : 使用
  • STM32调试过程中常见的问题及解决方法 一、 “Debug选项卡”下设置好仿真器的类型后,下载程序时却提示“No ULINK Device found.”    解决办法: Keil MDK默认使用ULINK仿真器下载程序“Project -...
  • 驱动程序调试常用方法

    千次阅读 2017-07-09 11:39:11
    驱动程序开发的一个重大难点就是不易调试。本文目的就是介绍驱动开发常用的几种直接和间接的调试手段,它们是: 利用printk 查看OOP消息 利用strace 利用内核内置的hacking选项 利用ioctl方法 利用/proc 文件...
  • c/c++ 程序调试方法

    千次阅读 2019-01-08 10:34:05
    总结一下自己常用的c/c++程序调试方法,首先介绍一下我的开发环境 系统 Linux xx 3.2.0-4-686-pae #1 SMP Debian 3.2.60-1+deb7u1 i686 GNU/Linux 编辑器 VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Feb ...
  • GDB+GdbServer: ARM程序调试

    万次阅读 2011-07-22 12:59:36
    内容摘要 远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接。使用 GDB标准程串行协议协同...调试stub是嵌入式系统的一段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。 就目前而

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 307,862
精华内容 123,144
关键字:

在程序调试过程中注意什么