debug teclipse单步调试执行后。如果要回到初始的地址 重回第一步。如何命令 谢谢。我是菜鸟~~~

【菜鸟的学习笔记】C之精华记录——捌(预处理、程序调试、编程风格) - 推酷
【菜鸟的学习笔记】C之精华记录——捌(预处理、程序调试、编程风格)
C预处理器是一种简单的宏处理器。它在编译器读取源程序之前对C程序的源文本进行处理。预处理器一般从源文件中删除所有的预处理器命令行,并在源文件中执行这些预处理命令所指定的转换操作。
【宏只是进行简单的文本替换】
所有的源文件行(包括预处理器命令行)都可以在行末加个反斜杠( \ )进行续行。这个操作发生在对预处理器命令进行扫描之前。
【注意:续行符反斜杠之后不能有任何字符,尤其注意检查不能有空格等空白符。】
普通宏定义
#define 命令有两种形式,取决于被定义的宏名后面是不是紧随一个左括号。若没有左括号,则为无参宏定义。
无参宏定义常用于:
1、在程序中引入名称常量。这样,可以在一个地方编写,然后通过名称在其它地方被引用,这样,以后修改这个数字就非常方便了。
2、改变外部定义的函数名或变量名。(有些外部函数的函数名过于简短或是与当前程序的命名风格不符,我们可以用宏定义一个新的函数名来代替它)
例:#define& error_handler &eh73
//我们用一个更具描述性的函数名error_handler来表示外部函数eh73
带参数的宏
左括号必须紧随宏名之后,中间不能有空格。如果宏名和左括号之间被一个空格所分隔,则这个宏被定义为不接受任何参数,并且宏体从左括号开始。
1、为了保证宏展开的正确性,应该给每个宏参数加上括号,且给整个表达式也加上括号。
(多余的括号保证了复杂的实际参数不会被编译器错误的解释)
2、使用类似函数的宏,可能存在一些陷阱。我们在调用宏函数时,会习惯地加一个分号,而额外的分号可能引发错误。
例:#define& SWAP(type, x, y)& { type _temp=x; x=y; y=_ }
若 if( x & y) SWAP(int , x, y) ;
&&&&&& elsex =
//这将产生错误,宏展开后有一个多余的分号,将导致else悬空。
★为了避免这个问题,可以把宏函数体定义为一条do-while语句
,后者可以接受在末尾添加分号。
#define&SWAP(type, x, y)& \
do { type _temp=x; x=y; y=_ } while(0)
3、宏参数的副作用。(当宏参数含++、--操作符时一定要小心)
例:#define SQUARE(x)& ((x)*(x))
若 b =SQUARE(a++) ; &&&&& //则结果是未定义的,因为(a++)*(a++)的行为取决于编译器。
真正的函数调用不会出现这样的问题,真正的函数调用是先计算参数值,然后再调用函数。而宏函数,只是简单的文本替换。
【宏是与类型无关的,即
其可以用类型做参数
。故:宏有时可以完成无法用函数实现的任务】
例:#defineMY_MALLOC( n, type )& ((type*)malloc((n)*sizeof(type)))
取消宏定义:
# undef命令可以取消定义一个名称为宏:undef& name
条件编译指令允许预处理器根据一个经过计算所得出的条件,来选择不同的语句参加编译。
#if& 常量表达式
&&&&&& 文本行组1
&&&&&& 文本行组2
常量表达式包括整数常量以及所有的整数算术、关系、位和逻辑操作符。
如果它的值不是0,则“文本行组1”则被编译器进行编译,而“文本行组2”则被丢弃。
defined操作符
defined 操作符只能在#if和#elif表达式中使用,而不能用于别处。
形式:definedname 或 defined(name)
#if&defined( VAX )& 可等同于 #ifdef VAX
但defined的使用更加灵活一些:
例:#ifdefined(VAX) && !defined(UNIX) && debugging
预定义的宏
标准C的预处理器定义了一些宏,这些宏的名称都是以两个下划线字符开始和结束的。程序员不能取消这些预定义宏的定义或对它们进行重新定义。
几个常用的预定义宏:
__LINE__&&&&&&&&&&&& 当前源程序行的行号,用十进制整数常量表示
__FILE__&&&&&&&&&&&&& 当前源文件的名称,用字符串常量表示
__DATA__&&&&&&&&&&&& 编译时的日期,用“Mmm dd yyyy”形式的字符串常量表示
__TIME__&&&&&&&&&&&& 编译时的时间,用“hh:mm:ss”形式的字符串常量表示。
一、使用断点和单步执行
详情请参阅具体的IDE使用说明
二、条件编译
#ifdef&DEBUG
&&&&&& printf(“File:%s line:%d, x=%d, y=%d”, __FILE__, __LINE__, x, y ) ;
如果要编译它,只要使用#defineDEBUG 即可,如果要忽略它,注释掉即可。
C99引入了一个预定义标识符:__func__
这个标识符可以由调试工具使用,打印出外层函数的名称。
例:if(failed)& printf(“Function %s failed \n”, __func__) ;
三、使用断言&assert.h&
断言就是声明某种东西应该为真。(预测某个值为多少,符合条件则继续,否则中止程序)
void&assert( int express ) ;
当它被执行时,对表达式参数进行测试。
如果它的值为假(零),它就向标准错误打印一条诊断信息并中止程序。
否则它不打印任何东西,程序继续执行。
例:assert(value != NULL ) ;
//如果它接受了一个NULL参数,则打印类似:assertfailed :value != NULL.file.c line 273
断言只是在测试阶段,防御性地测试某个变量值的方法
,不要再断言中写一些会对程序造成影响的表达式。因为在release版编译器会删除断言,若断言中的表达式对程序有影响,可能会产生错误!】
当程序被完整地测试完毕之后,在源文件的头文件assert.h被包含之前,增加定义:
#define NDEBUG
当NDEBUG被定以后,预处理器将会丢弃所有断言。
编程风格:
该名字要完全、准确地表述出该变量所代表的事物。
一个好名字通常表达的是“什么”(what),而不是“如何”(how)。
如果一个名字反映了计算机的某些方面而不是问题本身,那么它反映的就是“how”而非“what”了,
请避免选取这样的名字,而应该
在名字中反映问题本身
(一条员工数据:称作:inputRec或employeeData。inputRec是一个反映输入、记录 这些计算机术语的,不能反映问题特征)
当变量名的长度在10到16个字符时,调试程序所花的力气是最小的。
把限定词加到名字最后
,变量名最重要的部分,即
为变量赋予主要含义的部分应当位于最前面
特例: Num的限定词的位置是约定俗成的。
Num放在变量的开始位置代表一个总数;例:numCustomers表示员工总数
Num放在变量名的结束位置代表一个序号;例:customerNum表示员工号
避免此问题的方法:
Total来代表总数,用Index来代表序号
例:customerCount员工总数 customerIndex 员工序号
命名的一致性可提高可读性,简化维护工作。
如果你发现自己需要猜测某段代码的含义时,就该考虑为变量重新命名。
变量名中的对仗词
next/previous
source/destination&
。。。。。
1、为状态变量命名
标记的名字中不应该含有flag。标记应该用枚举类型、具名常量。
dataReady recalaNeeded 都是好名字
2、为布尔变量命名
以下是几个推荐的布尔变量名(可在其前加上具体的描述名称)
done:用done表示某件事已经完成。(在事情完成之前把done设为false,在完成之后设为true)
error:用error表示有错误发生。(在错误发生之前把变量值设置为false,在错误已经发生时把它设置为true)
found:用found来表示某个值已经找到了。(在还没有找到该值的时候把它设为false,找到之后设为true)
success或ok 用来表明一项操作时候成功。
(不要在布尔变量的前面加上Is)
命名规则可以根据局部数据、类数据、全局数据的不同而有所差别。
命名规则可强调相关变量之间的关系
命名规则的指导原则
&&&&&& 区分
变量名和子程序名
&&&&&& 变量名和对象名以小写字母开始,子程序名以大写字母开头。
&&&&&& 区分
&&&&&& 1、通过对对象采用更明确的名字区分类型和变量
&&&&&& 例:Widget employW
&&&&&& 2、通过给变量加&a&前缀区分类型和变量
&&&&&& 例:Widget aWidget&&&&& ;
&&&&&& 标识
&&&&&& 在全局变量名前加上&g_&前缀
&&&&&& 标识
&&&&&& 在成员变量名前加上&m_&前缀,可明确表示该变量既不是局部变量,也不是全局变量。
&&&&&& 标识
自定义类型
&&&&&& 在自定义类型名前加上&t_&前缀,可明确表示一个名字是类型名,可避免类型名与变量名的冲突
&&&&&& 标识
&&&&&& 在枚举类型名前加&e_&前缀,同时为该类型的成员名增加特定类型的前缀。
&&&&&& 例:Color_或Planet_
&&&&&& 标识
&&&&&& 在其前加上 const前缀,可防止给只读变量赋值的错误。例:constMax
变量名要包含以下三类信息
&&&&&& 1、变量的内容(它代表什么)
&&&&&& 2、数据的种类(具名变量、简单变量、用户自定义类型、类)
&&&&&& 3、变量的作用域(局部的、类的、全局的)
关于子程序
好的子程序名
&&&&&& 给子程序命名的重点是尽可能含义清晰,即:子程序的长短要视该名字是否清晰易懂而定。
&&&&&& 子程序的名字应当描述其所有输出结果以及副作用。
&&&&&& (例:一个子程序的作用是计算报表总额并打开一个输出文件。若把它命名为computeReportTotals()还不算完整。computeReportTotalsAndOpenOutputFile()很完整但是名字太长。解决方法是 你应该换一种方式编写程序,直截了当地解决问题而不产生副作用。[即:UNIX的哲学,让一个模块只干一件事!])&&&&&
&&&&&& 给子程序起名时要用动词加宾语的形式。例:PrintDocument()
&&&&&& 在面向对象语言中,不必在过程名中加入对象的名字,因为对象本身就已经包含在调用语句中了。例:Document.Print() ;
【子程序的名字是它质量的指示器,如果名字糟糕且又不准确,那么它就反映不出程序是干什么的。糟糕的名字都意味着程序需要修改】
正确地使用输入参数
&&&&&& 1、对于在函数体中不变更的参数,用const关键字来限制。
&&&&&& 2、如果你假定了传递给子程序的参数具有某种特征,那就要对这种假定进行说明。比注释还好的方法是在代码中使用断言(assertions)
[对参数接口的假定进行说明:
1、参数是仅用于输入的、要被修改的、还是仅用于输出的
2、表示数量的参数的单位(英寸,米等)
3、所能接受的数值范围
4、不该出现的特定数值
5、说明状态代码和错误值的含义]
如果你向很多不同的子程序传递数据,就请把这些子程序组成一个类,并把那些经常使用的数据用作类的内部数据。
如果你觉得把输入、修改、输出参数区分开很重要,那么就建立一种命名规则来对它们进行区分。
可在这些参数名之前加上i_m_ o_ 前缀。也可以用Input_Modify_ Output_ 来当前缀
把对子程序的调用和对状态值的判断清楚地分开
。把对子程序的调用和状态值的判断写在一行代码中,增加了该条语句的密度,也相应增加了其复杂度。
应该这样:
ouputStatus = report.FormatOutput(formattedReport ) ;
if( outputStatus = Success ) then ...
通常认为,用宏来代替函数调用的做法具有风险,而且不易理解,因此,除非必要,否则应该避免使用这种技术。
用给子程序命名的方法给宏函数命名,以便在需要时可以用子程序来替换宏。
宏对于支持条件编译非常有用,但对于细心的程序员来说,除非万不得已,否则是不会用宏来代替子程序的。(可用内联函数来实现宏函数的效果)
节制使用inline子程序!
建议在真正需要用空语句时这样写:
而不是单用一个分号,这就好比汇编里面的空指令,这样做可以明显的区分真正必须的空语句和不小心多写的分号。
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环的次数。
循环要尽可能的短,要使代码清晰,一目了然。
(如果你写的一个循环的代码超过一屏,那么会让读代码的人抓狂的。解决的办法有两个:
第一:重新设计这个循环。确认是否这些操作都必须放在这个循环里;
第二:将这些代码改写成一个子函数。循环中只调用这个子函数即可)
对于全局数据(全局变量、常量定义等)必须要加注释。
注释代码段时应注重“为何做(why)”,而不是“怎么做(how)”
对于函数的入口出口参数及函数的功能给出注释。
如果你的全局变量不用来多文件共享,那么就加上static,防止同一个载入模块的两个不同外部对象的命名冲突。
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
没有分页内容
图片无法显示
视频无法显示
与原文不一致VC++6.0&Debug单步调试简单入门
Debug单步调试简单入门&&
17:16:02|&&分类:
|&&标签:&&&&&&&&&&
|字号大中小&订阅
本篇文章为大家简单介绍如何使用VC++6.0的Debug来设置断点,进行单步调试。熟练使用Debug单步调试后,你找出并改正bug的速度和效率将大大提高,所谓磨刀不误砍柴工呀!
相信大家对谭浩强童鞋都不陌生,想当年,是他引领我们步入了C的殿堂,我们从他那里学会了如何写代码,他却没有教我们如何Debug,而我们伟大的老师,也对此只字不提。相信很少有人可以一次性写出完全正确的代码。对于我们这些个菜鸟来说,写出不带bug的代码倒是一件很不正常的事情。也许你知道有Debug这么个东西,但却不知道该怎样用;也许你还停留在在代码中添加N个printf来输出查看到底是哪里出了问题;也许……总之,经验表明,你花费时间看完这篇文章并学会简单的使用Debug,绝对不是浪费时间!
废话少说,进入正题:
0 error(s), 0 warning(s)
0 error(s), 0 warning(s)
当你按捺不住激动滴心情点击运行后,发现结果并不是你想要的结果……郁闷了。然后你在代码中加了n条printf来查看变量的结果……n多循环……运行,再加printf,again
and again……终于,要抓狂了……
好吧,同学,如果你会用也许你不用这么纠结。
下面通过一简单例子说明如何使用Debug的一些“基本”(我也只是刚入门的小菜鸟,高级的修行要靠自己的了)功能:
写了如图中的一个简单程序,编译链接都没有错误,运行结果却不理想(不正确)
需要指出的是,主函数不要再用()了,这种只有在你学的环境才不会出错,到别的(linux编译器)地方编译是通过不了的。main函数必须要有返回值,如写成int
main()在函数结尾时加一个return 0;,这样,所有编译器都不会报错了。
&最终结果确定是逻辑错误,如果不用单步调试,很难找出这种错误的。
这里先提到一个的概念,,既是在你需要的地方让它断开,如果你在某一行代码处添加了断点,那么程序运行到断点处即会暂停,不再继续往下运行,直到接到你继续运行的命令。
对上边示例的程序,在你感觉可能有问题的地方添加断点(按快捷键F9或者点击图中小手按钮),以便运行到断点处好查看运行状态。
值得注意的是,主函数调用的函数,只当作一步,如果你需要检查被调用的函数有没有问题,那么你需要在被调用的函数中添加断点,这样才能一步一步执行被调函数。
&在需要的地方添加完断点后(其实,在每个函数第一个需要停下来的地方添加断点就可以了,剩下的地方都可以用F10单步执行,某些已经验证过正确的函数,就不需要每次进行查看了)
添加完断点,按F5或者下图中的调试按钮,即可出现调试界面。如下图所示。同时出现的还有一个黑色的窗口,相信你不陌生,在某些需要输入数据的地方,可以在那个黑色窗口中输入。
&图中箭头所指的既是当前要运行的位置。左下窗口动态显示参与当前行运行的变量及其值,运行是变量值发生改变的会用红色标出。右边窗口中,你可以输入要查看的变量,它将一直显示在那里,等于是对左边动态显示的一个补充吧,对需要长期监视的变量很有用。
按即可进行单步运行,每按一下执行一步。你可以观察每一步,每个变量的状态。
&观察一圈发现,i的值总是大于j的,而第三重循环for(k=i;k&j
;k++)是永远无法进入循环的。因此找到了问题的症结,该怎么改,就看程序设计的了。
&像这种逻辑错误,不用单步调试,很难发现。即使用Debug也需要很长时间和耐心才可以找到,因此,我们编程时应该尽量避免这种逻辑上的错误出现。
调试过程中你可以直接修改代码,下一次运行到这里会按新的代码执行。调试完成想要退出Debug,你会发现,关那个黑窗口并不好使。直接在调试菜单中选择吧,这样才会安全退回到你原来的编辑界面。
&罗哩罗嗦一大堆,不知道你是否看明白了。也许明白的人也被我给说糊涂了。如果你看了这篇文章,感觉有些作用或者感觉很垃圾或者你有什么建议,都期待你能留下些什么……这是一个帮我改正错误的一个很好的方法。
PS:补充:
最近看《麻省理工:计算机科学编程导论》的时候讲到调试时需要注意的事情。感觉挺好,特记录下来。(另,课程中提到,“print”和“重新阅读代码并思考”是很重要的方法。确实,有时候调试工具的单步调试会让你局限于细节,而没有从整体上去观察思考代码。不过有时候调试工具也能给我们带来很大帮助。也许两者结合起来会让调试更加有效率吧)
自变量顺序错误。(注意参数命名,以避免颠倒顺序。实参和形参用相同的名字会调理清晰)
拼写错误。
忘记初始化。
对象与值相等。“==” 与" =
别名。数组、链表的深度复制和浅复制。
副作用。函数执行过程可能会改变一些变量的值。
收集自己经常犯的错误,调试时先从易犯的错误下手。
记录你尝试过的修改,调试用的“print”可以注释掉而不是删除。
调试别人代码的时候,调试的是代码,而不是注释。不要被注释所迷惑。
寻求帮助。旁观者清,寻找别人帮助,尽可能向别人解释清楚自己的程序,也许你在解释的过程中就能发现错误了。
清醒一下大脑。
欲速则不达。考虑好修改方案,而不是急功近利。修改这个bug的过程可能会产生更多的bug。
代码不能总是变长。代码写的越多,出错误的可能就越大。当你遇到问题时,试着把你的代码整理一下,整理的过程中也许你就可能找到错误。
及时备份旧版本代码。确保你的代码能够回到Debug前。没有什么比你Debug
4个小时,最后发现还没有4个小时前好,更令人沮丧的是你不能回到最开始的状态。硬盘空间很廉价,多保存一下旧版本的代码绝对没有坏处。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。汇编菜鸟求助_百度知道
汇编菜鸟求助
DATASTART,ARRAY+2
MOV TABLE+2,ARRAY+1
MOV TABLE+1,AL
MOV AL, DS:
MOV AXDATA
ARRAY DB 30H。不知道代码哪里错了CODE SEGMENTASSUME
ENDS程序没有达到目的,DATA
MOV DS,ARRAY
MOV TABLE,ALMOV AH,AX
MOV AL:CODE,50H
TABLE DB 3 DUP (,40H
jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src="http.hiphotos.baidu.baidu.baidu<a href="http://g.com/zhidao/wh%3D600%2C800/sign=c510fae91ea1cbb051fbbc3b4aed2e738ad4e6c5://g.com/zhidao/wh%3D450%2C600/sign=715b06df5c09af360b1fbbc3b4aed2e738ad4e6c5.jpg" esrc="http./zhidao/pic/item/b21bb051fbbc3b4aed2e738ad4e6c5://g
提问者采纳
你debug后按输入g命令运行大神啊
,就出现你想要的结果了,但是调试时你debug后,最后再d查看内存。,不运行代码?,怎么会达到目的呢,或输入t命令单步执行。,你的代码没有错误
提问者评价
吼吼,原来是这样^ .. ^,谢谢
其他类似问题
为您推荐:
其他1条回答
也就是说你用AL存地址应该是传送数据不匹配吧,地址是以16位保存的我觉得你的问题i出在。个人理解。
但是编译成功了,无警告无错误,
汇编的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 eclipse单步调试 的文章

 

随机推荐