分类目录归档:编程

cmd对话框中Debug指令学习

cmd对话框中Debug指令学习
一、DEBUG的主要指令:

点击开始–>点运行–>在运行对话框中输入cmd–>在输入debug


1、显示存储单元的指令D(DUMP)格式为:_D或_D

例如按指定范围显示存储单元内容的方法为:
-d100 120
18E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G…8.G…..G…
18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW.7
18E4:0120 8B

其中0100至0120是DEBUG显示的单元内容,左边用十六进位表示每个位元群组,右边用ASCII字元表示每个位元群组,. 表示不可显示的字元。这里没有指定段位址,D指令自动显示DS段的内容。如果只指定首位址则显示从首位址开始的80个位元群组的内容。如果完全没有指定位址则显示上一个D指令显示的最后一个单元后的内容。


2、修改存储单元内容的指令有两种。

☆输入指令E(ENTER)有两种格式如下:
第一种格式可以用给定的内容表来替代指定范围的存储单元内容。指令格式为:
-E address
例如:-E DS:100 F3’XYZ’8D
其中F3,’X’,’Y’,’Z’和各占一个位元群组,该指令可以用这五个位元群组来替代存储单元DS:0100到0104的原先的內容。

第二种格式则是采用逐个单元相继修改的方法。指令格式为:
-E address
例如:-E DS:100
则可能显示为:
18E4:0100 89.-
如果需要把该单元的内容修改为78,则使用者可以直接键入78,再按”空格”键可接著显示下一個單元的內容,如下:
18E4:0100 89.78 1B.-
这样使用者可以不断修改相继单元的内容直到用ENTER键结束该指令为止。

☆填写指令F(FILL)其格式为:
-F range list
例如:-F 4BA:0100 5 F3’XYZ’8D
使04BA:0100~0104单元内含特殊的五个位元群组的内容。若果list中的位元群组数超过特殊的范围,则忽略超过的项;若果list的位元群组数小於特殊的范围,则重复使用list填入,直到填满特殊的所有单元為止。


3、检查和修改寄存器内容的指令R(register)它有三种格式如下:

☆显示CPU内所有寄存器内容和标志位状态其格式为:
-R
例如:-r
AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC
18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000

☆显示和修改某个寄存器内容其格式为:
-R register name
例如:键入-R AX
系统将响应如下:
AX F1F4

即AX寄存器的目前内容为F1F4,如不修改则按ENTER键、否则可键入欲修改的内容,如:
-R bx
BX 0369
:059F
则把BX寄存器的内容修改为059F。

☆显示和修改标志位状态指令格式为:
-RF系统将响应,如:
OV DN EI NG ZR AC PE CY-
此时如不修改其内容可按ENTER键,否则可键入欲修改的内容如:
OV DN EI NG ZR AC PE CY-PONZDINV
即可,可见键入的顺序可以是任意的。


4、执行指令G其格式为:

-G[=address1][address2[address3…]]
其中位址1指定了执行的起始位址,如不指定则从目前的CS:IP开始执行。后面的位址均为断点位址,当指令执行到断点时,就停止执行并显示目前所有寄存器及标志位的内容,和下一笔将要执行的指令。


5、追踪指令T(Trace)有两种格式:

☆逐條指令追蹤:
-T [=address]
从指定位址起执行一条指令后停下来,显示所有寄存器内容及标志位的值。如未指定位址则从目前的CS:IP开始执行。

☆多条指令追踪:
-T [=address]
从指定位址起执行n条指令后停下来,n由value指定。


6、汇编指令A(Assemble)其格式为:

-A
该指令容许键入汇编语系语句,并能把它们汇编成机器代码,相继地存放在从指定位址开始的存储区中。必须注意:DEBUG把键入的数字均看成十六进位数,所以如要键入十进位数,则其后应加以说明,如100D。


7、反汇编指令U(Unassemble)有两种格式。

☆从指定位址开始反汇编32个位元群组其格式为:
-U
例如:
-u100
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
18E4:0112 BBO4O2 MOV BX,0204
18E4:0115 E80200 CALL 011A
18E4:0118 CD20 INT 20
18E4:011A 50 PUSH AX
18E4:011B 51 PUSH CX
18E4:011C 56 PUSH SI
18E4:011D 57 PUSH DI
18E4:011E 8B37 MOV SI,
若果位址被省略,则从上一个U指令的最后一条指令的下一个单元开始显示32个位元群组。

☆对指定范围内的存储单元进行反汇编,格式为:
-U
例如:
-u100 10c
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202

-u100 112
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
可见这两种格式是等效的。


8、命名指令N(Name)其格式为:

-N filespecs
指令把两个档案标识符格式化在CS:5CH和CS:6CH的两个档案控制块中以便在其后用L或W指令把档案装入存盘。filespecs的格式可以是:
[d:] filename[.ext]
例如:
-N myprog
-L
可把档案myprog装入存储器。


9、装入指令(Load)有两种功能。

☆把磁碟上指定扇区范围的内容装入到存储器从指定位址开始的区域中。其格式为:
-L[address[drive sector sector]

☆装入指定档案其格式为:
-L
此指令装入已在CS:5CH中格式化了档案控制块所特殊的档案。如未指定位址则装入
CS:0100开始的存储区中。


10、写指令W(Write)有两种功能。

☆把资料写入磁碟的指定扇区。其格式为:
-W address drive sector sector
☆把资料写入特殊的档案中。其格式为:
-W
此指令把特殊的存储区中的资料写入由CS:5CH处的档案控制块所特殊的档案中。如未指定位址则资料从CS:0100开始。要写入档案的位元群组数应先放入BX和CX中。


11、离开DEBUG指令Q(Quit)其格式为:
-Q
它离开DEBUG、返回DOS。本指令并无存盘功能,如需存盘应先使用W指令。

==========================================================================
问题:初学者问一个低级问题,执行debug-a后如果有一行输入错误,如何变更这一行?

回答:加入进行如下输入

D:\PWIN95\Desktop>debug
-a
2129:0100movax,200
2129:0103movbx,200
2129:0106movcx,200
2129:0109

此时发现movbx,200一句错误,应为movbx,20可以敲Enter返回”-“状态然后输入:
-a103
2129:0103movbx,20
如果是多或是少若干行不必重新输入、可以用M指令移动后面的程式来去掉或是增加程式空間。


问题:如何除错和汇编你的第一个PC x86汇编语系程式呢?

回答:以下这些简单的解释可以让一个汇编语系新手使用DEBUG

00) 在使用时如何快速获得debug的使用帮助呢?
01) 让我们开始工作吧例如:显示BIOS的日期。
02) 在你的电脑的COMMANG.COM档案里搜寻”IBM”这几个字元。
03) 一位十六进位数的运算。
04) 检查x86寄存器内容。
05) 我们来编写我们的第一个用机械语系编写的程式-列印一个字元。
06) 我们现在用汇编语系指令来做和例5一样的事情。
07) 现在,我们不但要编写一个汇写程式式,而且我们还要把它存盘。
08) 现在,我们试一试检视一个已经编好的程式。
09) 你可以用DEBUG的计算功能计算程式的长度。
10) 另一种显示在萤幕上字串的方法。
11) 让我们试一试反覆输出。
12) 我们现在把两个程式连线起来。
13) 让我们逐步执行这个刚刚修补的程式。
14) 如果一开始的指令不是跳转指令那麼可能就要用这种方法了。

以下所有的指令都是可以执行在WIN98/ME/2000/XP/2003的MS-DOS或CMD模式下的。进入MS-DOS或CMD的模式有:

[开始][程式][MS-DOS模式]
[开始][运行][开启]CMD[确定]
或是你可以按两下它:
C:WindowsCommand.com


00) 在使用时,如何快速获得debug的使用帮助呢?

以下PROMPT>表示目录提示符:一般为:C:WINDOWSCOMMAND

PROMPT> DEBUG /?<按Enterpress the enter key now>
怎样?出错了吧。显示如下:
C:WINDOWS>DEBUG/?
Runs Debug, a program testing and editing tool.
DEBUG [[drive:]filename [testfile-parameters]]
[drive:]filename Specifies the file you want to test.
testfile-parameters Specifies command-line information required by
the file you want to test.
After Debug starts, type ? to display a list of debugging commands.
因为错了所以它给你显示一些提示。留意到最后一句了吗?

现在我们再来试一试:

PROMPT> DEBUG<按Enter> (注意, DEBUG程式的指令是在一条横线”-“后出现的。)-?<在出现的横线后面输入?再Enter>(下面的内容是按字母顺序排序的)(注意:Note: Don’t type the dash or comments — just the ?)

显示如下但是没有中文的哦中文是我加上去的:
汇编assemble A
比较compare C range address
倾倒dump D
进入enter E address
填充fill F range list
进行go G [=address]
十六进位hex H value1 value2
输入input I port
装载load L
移动move M range address
命名name N
输出output O port byte
进行proceed P [=address]
离开quit Q
纪录register R
搜寻search S range list
描述trace T [=address]
反汇编unassemble U
寫write W
分配延伸记忆体allocate expanded memory XA [#pages]
释放延伸记忆体deallocate expanded memory XD
map expanded memory pages XM
display expanded memory status XS
-q<按Enter> (这是离开DEBUG回到DOS状态This quits out of debug, returning to the DOS prompt)

(Tested examples below walk the user thru the following debug examples:在下面的例子里读者必须明白以下几条DEBUG指令。)

-D 显示一定范围记忆体的内容Display the contents of an area of memory
-Q 离开DEBUG程式Quit the debug program
-S 搜寻Search for whatever
-H 十六进位的运算Hex arithmatic
-R 显示或是改变一个或是多个寄存器的内容Display or change the contents of one or more registers
-E 输入资料进入记忆体,在一个详细的位址里Enter data into memory, beginning at a specific location
-G 执行现在在记忆体里的程式。Go run the executable program in memory
-U 反汇编,把我们不认识的机械代码变为我们可以认识汇编语系符号Unassemble machine code into symbolic code
-T 描述一條指令的用法。Trace the contents of one instruction
-P 进行或是执行一个关联的指令Proceed, or execute a set of related instructions
-A 编译,把汇编指令变为机械代码Assemble symbolic instructions into machine code
-N 命名一個程式Name a program
-W 把一个已经命名的程式写进磁碟Write the named program onto disk
-L 把程式装载进记忆体Load the named program back into memory


01) 让我们开始工作吧例如:显示BIOS的日期。

(以下PROMPT>表示目录提示符:一般为C:WINDOWSCOMMAND)
PROMPT> DEBUG<按Enter>
-D FFFF:0006 L 8<按Enter>(显示 FFFFh, 偏移位址 6h, 长度 8 bytes)
在小弟的电脑上这里显示为 “1/10/96.”译者的电脑显示” FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00.”相信小弟的电脑里也是用这种格式显示的。这里显示出来的是使用者BIOS的日期,有兴趣的话可以重新开机看看,注意开机时的显示。
-Q<按Enter> (离开DEBUG)
思考:当只按DEBUG的时候,编辑的是什麼?为什麼可以找到BIOS的日期?(译者认为可能是记忆体的真实物理位址。)


02) 在你的电脑的COMMANG.COM档案里搜寻”IBM”这几个字元。

下面的”C:Win95″是根据每不电脑不同的。像译者的电脑里就是”C:WINDOWS”
PROMPT> DEBUG C:Win95Command.com<按Enter>
-S 0 L FFFF “IBM”<按Enter>(从0开始搜寻”IBM”,搜寻FFFFh多个单元格)
-Q<按Enter> (离开DEBUG)

以下是译者做的:

C:WINDOWS>DEBUG C:WINDOWSCOMMAND.COM
-S 0 L FFFF “IBM”
-S 0 L FFFF “COMMAND”
12A7:008D
12A7:04F7
12A7:3870
12A7:38BE
12A7:38DD
-S 0 L FFFF “PATH”
12A7:38AD
12A7:CCB7
12A7:CF55
-S 0 L FFFF “COMSPEC”
12A7:38D4
12A7:3A4D
12A7:CCC4
-Q
C:WINDOWS>

(注意:搜寻是要区分大小写的)
(你可以看到上面是没有找到”IBM”的, 可以试一试”PATH” , “COMSPEC” , “COMMAND”)
(注意: 这种方法用在寻找加密资料和已被移除的资料等方面时是十分有用的)


03) 一位十六进位数的运算:

PROMPT> DEBUG<按Enter>
-H 9 1<按Enter> (加减两个十六进位的数,9h+1h=Ah & 9h-1h=8h)
结果是显示: 000A 0008
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-h 9 1
000A 0008
-q
C:WINDOWS>


04) 检查x86寄存器内容。

PROMPT> DEBUG<按Enter>
-R<按Enter>(显示x86寄存器内容)
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 043C ADD AL,3C
-Q

下面是对寄存器的简单介绍:

资料存储器:
在本类中,一般讲的AH就是AX的前八位,AL就是AX的后八位,后面的以此类推。AX Accumulator;作为累加器,所以它是算术运算的主要寄存器。另外所有的I/O指令都使用这一寄存器与外部装置传输讯息。BX Base register;可以作为通用寄存器使用,此外在计算存储器位址时,它经常用作基位址寄存器。CX Counting register;可以作为通用寄存器使用,此外在循环(LOOP)和串处理指令中作隐含的计数器。DX Data register;可以作为通用寄存器使用,一般在作双字长运算时,把DX和AX群群组合在一起存放一个双字长数,DX用来存放高位字。此外,对某些I/O动作,DX可用来存放I/O的连线埠位址。

指标及变址寄存器:
BP Base pointers register ;机制指标寄存器。
SI Source index register ;堆栈指标寄存器。
DI Destiny index register ;目的变址寄存器。
SP Battery pointer register ;堆栈指标寄存器。

段寄存器:
CS Code segment register ;代码段寄存器,存放正在执行的程式指令。
DS Data segment register ;资料段寄存器,存放目前执行程式所用的资料。
SS Battery segment register ;堆栈段寄存器,定义了堆栈所在区域。
ES Extra segment register ;附加段寄存器,存放附加的资料是一个辅助性的资料区,控制寄存器。
IP Next instruction pointer register;指令指标寄存器,它用来存放代码段中的偏移位址,在程式执行的过程中,它始终指向下一笔指令的首位址,它与CS寄存器联用确定下一笔指令的物理位址。
F Flag register;标志寄存器 “NV UP EI PL NZ NA PO NC”就是了,也有人称之为PSW Program Status Wold程式状态寄存器 。

这里有一点必须讲明白的现在在,其实从奔腾开始这些寄存器(除了所有段寄存器,标志寄存器)都是32位的。并且加多了两个16位段寄存器FS,GS。dos下面看到这些寄存器是16位的。要看32位寄存器可以使用soft-ice。对於FS,GS的作用我也不是很清楚,希望有高手指点,谢谢。)


05) 我们来编写我们的第一个用机械语系编写的程式-列印一个字元。

(这里用机械语系的主要原因是考虑到有一些使用者不懂汇编指令,现在就要让他有一个认识电脑程式实质是一些数字)

PROMPT> DEBUG<按Enter>
-E 100<按Enter> (在偏移位址為100的地方輸入機械指令程式)
B4<按空格>02<按空格> (在AX寄存器的前八位存入02)
B2<按空格>41<按空格> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对著表改改数字试一试)
CD<按空格>21<按空格> (当AH=02时这是DOS显示输出的中断号)
CD<按空格>20<按Enter> (离开DOS)
-G<按Enter> (程式执行,并在萤幕上显示出”A”)
程式执行完以后你将看到”Program terminated normally”(程式标准结束了).
-U 100<按Enter> (我们把它反汇编,就是把机械指令变为汇编语系指令)

107F:0100 B402 MOV AH,02
:0102 B2 MOV DL,41
:0104 CD21 INT 21
:0106 CD20 INT 20
(下面会有一堆无用的东西)
(对了你的段位址可能与我的段位址CS=107F不同哦)

-R<按Enter>(让我们来看看寄存器的值; IP==100h, AX==0000h, DX==0000h)
好极了我们看到电脑又做好了准备下一次执行程式了。
-T<按Enter>(执行第一步动作… IP=>102h, AX=>0200h,指令指标寄存器指向下一笔指令,AX的值被改变。)
-T<按Enter>(执行第二步动作… IP=>104h, , DX=>0041h,指令指标寄存器指向下一笔指令,DX的值被改变。)
-P<按Enter>(继续执行 INT 21,IP=>106h, AX=>02h,)
-P<按Enter>(继续执行INT 20)
-Q<按Enter>(离开DEBUG)

(注意:你必须小心使用”T”.因为若果你在程式完结以后继续执行这条指令,因为我们无法知下面的指令是什麼,所以我们也无法预知它可能带来的后果)

C:WINDOWS>DEBUG
-E 100
127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20
-G
A
Program terminated normally
-U 100
127C:0100 B402 MOV AH,02
127C:0102 B241 MOV DL,41
127C:0104 CD21 INT 21
127C:0106 CD20 INT 20
127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009
127C:010E EB59 JMP 0169
127C:0110 57 PUSH DI
127C:0111 BFF1E3 MOV DI,E3F1
127C:0114 8BDF MOV BX,DI
127C:0116 06 PUSH ES
127C:0117 0E PUSH CS
127C:0118 07 POP ES
127C:0119 32D2 XOR DL,DL
127C:011B EB34 JMP 0151
127C:011D 006B12 ADD [BP+DI+12],CH
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-T
AX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC
127C:0102 B241 MOV DL,41
-T
AX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC
127C:0104 CD21 INT 21
-P
A
AX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC
127C:0106 CD20 INT 20
-P
Program terminated normally
-Q
C:WINDOWS>


06) 我们现在用汇编语系指令来做和例5一样的事情。

PROMPT>DEBUG<按Enter>
-A 100<按Enter>(在偏移位址为100的地方输入汇编语系程式)
MOV AH,02<按Enter>(选用DOS的02号功能呼叫,显示输出)
MOV DL,<按Enter>(在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对著表改改数字试一试)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”A”)
INT 20<按Enter>(离开DOS)
<按Enter>(结束汇编语系写程式状态,回到DEBUG指令状态)
-G =100<按Enter>(执行程式,其实可以不要”=100″因为一般预设启始位置是100)
-Q<按Enter>(离开DEBUG)

C:WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 INT 20
127C:0108
-G
A
Program terminated normally
-Q
07) 现在我们不但要编写一个汇写程式式而且我们还要把它存盘。

(下面这个程式就要比原来的程式复杂一点了-显示输出:”ABC”)

PROMPT> DEBUG<按Enter>(执行DEBUG程式;系统预设启始IP寄存器值为100h)
-A 100<按Enter>(用汇编语系编写一个程式,启始位址是100h)
MOV AH,02<按Enter>(选取DOS的02号功能呼叫, 显示输出)
MOV DL,<按Enter>(在DX寄存器的后八位存入41h,41h就是大写A的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”A”)
MOV DL,42<按Enter>(在DX寄存器的后八位存入41h,41h就是大写B的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”B”)
MOV DL,43<按Enter>(在DX寄存器的后八位存入41h,41h就是大写C的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”C”)
INT 20<按Enter>(程式结束,离开DEBUG)
<按Enter>(结束汇编指令输入,回到DEBUG指令输入)
-R BX<按Enter>(检视寄存器BX的值)
:0000<按Enter>(设定BX为0000h,这是程式的结尾位址是BX:CX)
(注意,只要BX = 0000, 档案的大小就小於 < 64 Kb.)
-R CX<按Enter>(设定CX为Fh,这是程式的长度:16位)
:0010<按Enter>(现在我们可以把这个16位元群组的程式写入硬碟了)
-N printabc.com<按Enter>(将要存盘的程式命名)
-W<按Enter>(把这十六位元群组写到档案里面)
-Q<按Enter>(离开DEBUG)
PROMPT> DIR printabc.com<按Enter>
这里将会报告这个档案的大小是16位元群组(10h 位元群组)
PROMPT> printabc.com<按Enter>
会马上在萤幕上列印出”ABC”

C:WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 MOV DL,42
127C:0108 INT 21
127C:010A MOV DL,43
127C:010C INT 21
127C:010E INT 20
127C:0110
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-R BX
BX 0000
:
-R CX
CX 0000
:0010
-N PRINTABC.COM
-W
Writing 00010 bytes
-Q
C:WINDOWS>DIR PRINTABC.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:WINDOWS
PRINTABC COM 16 03-21-01 11:02 PRINTABC.COM
1 file(s) 16 bytes
0 dir(s) 557,711,360 bytes free
C:WINDOWS>PRINTABC
ABC
C:WINDOWS>

这里可以有人告诉我为什麼要存入是BX:CX代表程式长度吗?


08) 现在我们试一试检视一个已经编好的程式:

PROMPT> DEBUG<按Enter>(执行DEBUG程式在CS:IP = CS:0100h)
-N printabc.com<按Enter>(告诉电脑你想装载的程式名)
-L<按Enter>(装载那个名字的程式进入记忆体)
-U 100 L 10<按Enter>(从偏移位址100开始反汇编16位位元群组)
-R<按Enter>(现在看看寄存器里面的内容)
注意:DEBUG本身是没有自动纪录档案大小的。
-G (执行被命名的程式,列印”ABC”)
(你将看到”ABC”,然后是”Program terminated normally”)

C:WINDOWS>DEBUG
-N PRINTABC.COM
-L
-U 100 L 10
12A4:0100 B402 MOV AH,02
12A4:0102 B241 MOV DL,41
12A4:0104 CD21 INT 21
12A4:0106 B242 MOV DL,42
12A4:0108 CD21 INT 21
12A4:010A B243 MOV DL,43
12A4:010C CD21 INT 21
12A4:010E CD20 INT 20
-R
AX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC
12A4:0100 B402 MOV AH,02
-G
ABC
Program terminated normally


09)你可以用DEBUG的计算功能计算程式的长度。

一开始的时候你的程式起始位址是在0100h:
107F:0100 MOV AH,02 <—–这就是 100h
你的程式的最后一行在010Eh:
107F:010E INT 20 <–最后一行
然后,最后一条指令的下一行的位址是0110h:
107F:0110 <–這就是110h
所以,从0110h里减去100h我们得到得长度是10h 位元群组.
PROMPT> DEBUG<按Enter>
-H 110 100<按Enter>(这条指令将运算110h+100h和110h-100h)
0210 0010<按Enter>(汇报 110h-100h=0010h; 16-byte 程式长度16位)
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-H 110 100
0210 0010
-Q
10)另一种显示在萤幕上字串的方法。

注意:在你输入资料的时候,按”-“键将会可以让你回退一格。

PROMPT> DEBUG<按Enter>
-E 200<按Enter> (从偏移位址200开始。输入”Hello,World”)
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h ?和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按Enter> (“Hello,World” 已经输入完毕)
-D 200<按Enter> (显示你刚刚输入的内容:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 … HELLO,WORLD$…)
-A 100<按Enter> (用汇编语系写一个新程式在IP-100h处开始)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫,显示字串)
MOV DX,0200<按Enter> (把输出位址(200h),放进寄存器)
INT 21<按Enter> (执行DOS功能呼叫,显示”Hello,World”)
INT 20<按Enter> (离开程式回到DOS状态)
<按Enter> (结束汇编语系输入,回到DEBUG输入状态)
-G<按Enter> (从 CS:IP开始执行程式, 就是从107F:0100h开始执行程式)
现在我们可以把这个程式储存进一硬盘:
-D 100<按Enter> (纪录:程式的起始点在100h)
-D 200<按Enter> (纪录:程式资料单元的结束点是在020Bh)
-H 20B 100<按Enter> (运算 20Bh-100h=10Bh;程式長度267位元群組)
-R BX<按Enter> (检查BX寄存器的值)
:0000<按Enter> (设定BX为0000h,程式的长度是BX:CX,实际上你可以把BX和CX写到一起,即实际长度为:0000010Bh,这样些的目的是使你可以计算更大的程式的长度)
-R CX<按Enter> (设定CX 为010Bh, 这就是这个程式的长度了)
:010B<按Enter> (现在你可以把这个108位元群组的程式写入硬碟了)
-N printhw.com<按Enter> (将要写入硬碟的程式命名)
-W<按Enter> (把这10Bh 即267个位元群组写入档案)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw.com<按Enter>
将会汇报程式的长度是267位元群组(10Bh位元群組)。
PROMPT> printhw.com<按Enter>
执行这个程式这将会在萤幕上显示出”Hello,World”:

C:WINDOWS>DEBUG
-E 200
127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F
127C:0208 CD.72 2F.6C 3C.64 00.24 C3.
-D 200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t… u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<“u… .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ….6….7..
127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6………
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y………
-A 100
127C:0100 MOV AH,09
127C:0102 MOV DX,0200
127C:0105 INT 21
127C:0107 INT 20
127C:0109
-G
Hello,World
Program terminated normally
-D200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t… u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<“u… .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ….6….7..
27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6………
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y………
-H 20B 100
030B 010B
-R BX
BX 0000
:
-R CX
CX 0000
:010B
-N PRINTHW.COM
-W
Writing 0010B bytes
-Q

C:WINDOWS>DIR PRINTHW.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:WINDOWS
PRINTHW COM 267 03-22-01 11:53 PRINTHW.COM
1 file(s) 267 bytes
0 dir(s) 555,089,920 bytes free

11)让我们试一试反覆输出:

PROMPT> DEBUG<按Enter>
-A 100<按Enter> (用汇编语系写一个新的程式,起始位址是100h)
JMP 125<按Enter> (从102h接前往125h)
<按Enter> (结束输入汇编指令。译者注:这里是为了例12做准备)
-E 102 ‘Hello World’ 0d 0a ‘$'<按Enter> (把字串输入记忆体)
-A 125<按Enter> (从125h开始继续编写我们的汇编语系程式)
MOV DX,0102<按Enter> (把字串的首位址(102h)放入DX寄存器)
MOV CX,0005<按Enter> (指定这条指令将被显示5次)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫, 显示字串)
INT 21<按Enter> (执行DOS的功能呼叫, 显示”Hello, World”)
DEC CX<按Enter> (每次执行到这里CX都减去1)
JCXZ 0134<按Enter> (如果计数器CX=0,那麼前往位址0134h)
JMP 012D<按Enter> (其他情况下,即CX≠O时前往012Dh)
INT 20<按Enter> (程式离开DOS状态)
<按Enter> (结束汇编语系程式输入,回到DEBUG)
-U 100<按Enter> (从位址100h 开始反汇编)
-U<按Enter> (继续执行反汇编指令,直至你看到INT 20)
-H 0136 100<按Enter> (运算程式长度为36h)
-U 100 L 36<按Enter> (从100h反汇编到136h ,来确认你的计算)
-R BX<按Enter> (检视寄存器BX的值)
:0000<按Enter> (设定BX为0000h)
-R CX<按Enter> (把CX 设定为36h, 这就是程式长度36位元群组)
:0036<按Enter> (现在你可以把这36位元群组写入档案了)
-N printhw5.com<按Enter> (命名我,我们要写入的档案名)
-W<按Enter> (把这36位元群组的内容写进新档案)
-G<按Enter> (执行程式,在萤幕上显示”Hello-World “)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw5.com<按Enter>
将会汇报档案大小为54位元群组,换算为十六进位就是36h位元群组
PROMPT> printhw5.com<按Enter>
将在萤幕上显示五次”Hello World”。


12)我们现在把两个程式连线起来。

我们现在把printhw.com做为修补程式写进printhw5.com,新版本的printhw5将先执行原来的printhw.com再执行原来的printhw5.com。

PROMPT> COPY printhw5.com printhw5.bak<按Enter>
首先,备份printhw5.com,以后可以用於比较
PROMPT> DIR printhw5.com<按Enter>
现在,检视到得仍然是以前的54位元群组(36h 位元群組)
PROMPT> DEBUG printhw5.com<按Enter>
-R<按Enter> (现在检视仍然是BX:CX=0000 0036h bytes)
-U 100<按Enter> (检视到最後的是 EB 23 (JMP 0125))
-H 100 36<按Enter> (最後的指令是在 100h+36h=136h)
-H 136 1<按Enter> (下一个可用的存储器位置是136h+1h=137h)

现在你拥有足够的资料去修补那个程式

-E 110<按Enter> (把”Hello,World”输入记忆体)
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h ?和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按Enter> (停止输入”Hello,World”)
-D 110<按Enter> (顯示更才输入记忆体的資料:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 …HELLO,WORLD$…)
-A 100<按Enter> (在IP位址的(100h)开始夺取原来的程式的控制权,原来这里是”JMP 125″)
JMP 137<按Enter> (代替原来执行的程式首先执行我们现在的修补程式)
<按Enter> (结束汇编指令输入,回到DEBUG指令输入)
-A 137<按Enter> (在下面的可用通奸编译这个修补程式)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫,显示输出)
MOV DX,110<按Enter> (把我们要输出的字段的首位址(110h)给DX寄存器)
INT 21<按Enter> (执行DOS 的功能呼叫,显示”Hello,World”)
JMP 0125<按Enter> (这里用跳转到原程式来代替离开到DOS指令(INT 20))
<按Enter> (结束汇编指令输入,回到DEBUG指令输入)
-U 125<按Enter> (确认一下源程式没有被我们误改了,如果误改了就马上离开DEBUG重新來過)
-U 100 L 1<按Enter> (确认已经使程式跳转到我们的修补程式位址137h)
-D 110 L C<按Enter> (确认资料区已经有了我们想要的资料)
-U 137<按Enter> (确认我们的新程式已经输入了)

现在我们可以把这个小程式存入硬碟了:
(注意:在现在整个程式的最后一条指令”JMP 0125″ 的后面一条的位址是0140h)

-H 0140h 100<按Enter> (計算140h-100h=40h; 答案是我们现在有一个长度为64位元群组的小程式)
-RBX<按Enter> (检查BX寄存器的值是否为”0″)
:<按Enter> (如果BX是0000h那麼就不需要改动啦)
-RCX<按Enter> (要把CX改为40h。这是我们的程式的长度)
:40<按Enter> (现在你可以把这0000:0040h个位元群组的小程式放入硬碟啦)
-W<按Enter> (覆盖我们的原程式)
-G<按Enter> (尝试执行我们的新程式)
-Q<按Enter> (离开DEBUG回到DOS)
PROMPT> DIR printhw5.com<按Enter>
现在你再看就发现文章大小不再是54位元群组, 变成了64位元群组.
PROMPT> printhw5.com<按Enter>
现在是首先在萤幕上列印”Hello,World”一次,然后再列印”Hello,World”5 次(注:这里其实可以在写程式的时候换一换内容试一试。)


13) 让我们逐步执行这个刚刚修补的程式:

PROMPT> DEBUG printhw5.com<按Enter>
-R<按Enter> (第1步:位址0100h内容是 EB35 “JMP 0137”)
-T<按Enter> (第2步:位址0137h内容是B409 “MOV AH,09”)
-T<按Enter> (第3步:位址0139h内容是BA1001 “MOV DX,0110”)
-T<按Enter> (第4步:位址0139h内容是CD21 “INT 21”)
-P<按Enter> (执行第5:”Hello,World”位址013Eh內容是EBE5 “JMP 0125”)
-T<按Enter> (到这里控制权已经回到了原程式)

如果你想的话你可以一步一步的执行完全部程式;方法就是一直按”T”直至到达下一个功能呼叫执行完成后。到那时按一个”P”就可以继续按”T”。

14)如果一开始的指令不是跳转指令,那麼可能就要用这种方法了:

例如:如果我们想叫程式printhw先列印”ABC”,就要取得控制权了。然后列印”ABC”的程式把控制权给回原来的printhw。在这个事例里printhw在100h的位址有两位元群组的程式;不能像上面那样简单的替代(一個JMP代替另一個JMP)就完事。解决办法就是使用NOP指令。

PROMPT> DIR printhw.com<按Enter>
将汇报程式的长度为267位元群组(10Bh 位元群組).
PROMPT> DEBUG printhw.com<按Enter>
-R<按Enter> (IP=100h 並且printhw’s 的档案大小=BX:CX=0000:010Bh)
-U 100<按Enter> (第一条指令B4 09 (MOV AH,09)是两个位元群组的)
(第二条指令是三个位元群组的 BA 00 02 (MOV DX,0200))
-H 100 10B<按Enter> (最后一条printhw的指令是在100h+10Bh=20Bh)
(DOS的INT 21功能呼叫是在105h开始的)

现在你有足够的资料输入你的程式了!

-A 100<按Enter> (要在printhw 的IP开始位置就夺取程式的控制权)
JMP 20B<按Enter> (前往20Bh增加一个程式)
NOP<按Enter> (用空指令填充直至你去到下一笔完整的指令)
NOP<按Enter> (你可以用它来覆盖你不想只执行的原程式指令 ,而不改变原来的位址。但是在这里我们只需要两个NOP)
注:为了使大家更加明白所以我将各条指令对应的机械指令的长度写在下面

B409 MOV AH,09
BA0002 MOV DX,0200
E90301 JMP 020B
90 NOP

这样我们就很清楚的看到JMP 020B的长度比MOV AH,09多了1个位元群组,但MOV DX,0200是3个位元群组,而NOP是空指令,是不执行任何动作的,它只是占1个位元群组。所以我们现在把前两条指令用一个JMP 020B和两个NOP代替。后面再加上去。

<按Enter> (结束汇编指令回到DEBUG指令输入)
-U 100<按Enter> (看一看前面我们做了些什麼)
(注意DOS INT 21中断任然是在 IP=105h的地方开始)
-A 20B<按Enter> (现在把我们的原程式写在后面)
MOV AH,02<按Enter> (选取DOS 的 2号功能呼叫, 字元显示输出)
MOV DL,41<按Enter> (在DL寄存器存入”A”的ASCII码41h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”A”)
MOV DL,42<按Enter> (在DL寄存器存入”B”的ASCII码42h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”B”)
MOV DL,43<按Enter> (在DL寄存器存入”C”的ASCII码43h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”C”)
MOV AH,09<按Enter> (现在重新输入原来在100h的程式指令)
MOV DX,0200<按Enter> (现在要打扫寄存器了,复原原来的200h的值)
JMP 105<按Enter> (前往INT 21指令的位置105h)
<按Enter> (请注意一下你这里最后的位址是0221h)
-H 221 100<按Enter> (计算221h-100h=121h 就是289位元群组的程式)
-R CX<按Enter> (把CX的值设为121h, 这就设定了程式的新长度)
:0121<按Enter> (现在用121h (也就是289位元群组)覆盖原值)
-W<按Enter> (把这289个位元群组写回原程式)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw.com<按Enter>
(现在在看就会是新程式的长度289位元群组而不是,267位元群组)
现在在萤幕上先出现”ABC”再出现”Hello,World”分享:

国内外3D网站大全

这是从网上收集的,并未一一验证,如有无效望见谅~

国内国外3D网站大全

http://china3d.51.net/一个较好的3DMAX个人图像网站

http://touch3.easthome.net/news.htm 第三类接触

http://www.acc.com.cn/ 亚洲电脑顾问公司–影视特技专业站点

http://hot3d.126.com/ 一个有抱负的三维制作者

http://person.zj.cninfo.net/~jr3d 欢乐梦想MAX主页 )

http://home.baoding.cn.net/~shuai4d 3D魔法学院(MAYA)

http://www.hunanmcb.com/dreamlight 另类时空

http://member.zz.ha.cn/grwy/wjitstudio 较为全面的多媒体站点

http://grwy.online.he.cn/luckyvideo 不多见的3D动画+音乐创作的站点

http://grwy.online.he.cn/pline 红蚂蚁3D工作室

http://www.btc.sh.cn/ 上海影视节目制作中心

http://member.netease.com/~cloudwu 风云工作室

http://www.chinadv.jlonline.com/ 又一个3D技术基地!

http://www/

http://www.eyeonline.com/ 非常漂亮的插件站点

http://www.3dcafe.com/ 最大的三维教学、模型基地

http://www.habware.at/ 3DMAX的免费插件下载

http://www.ping.be/maya MAYA的教学站点

http://www.highend3d.com/ 好的三维站点(MAYA、ALIAS、RENDERMAN、SOFTIMAGE)

http://www.highend2d.com/ highend3d的子妹篇

http://www.3dinteractive.com/ 提供三维教程、模型

http://www.geocities.com/ 提供Lightwave教程

http://www.3d.co.yu/ 提供Lightwave教程

http://www.3d-design.com/ 3D综合站点(3D软件、杂志、链结…)

http://dlf.future.com.au/ 3d动画练习、教程

http://www.dagallery.com/ Rhino教学

http://home3pnet.se/ 3D Artist站点

http://www.3dark.com/ 综合3D商业网站

http://www.lumis.com/ 强烈推荐顶级3D教学介绍站点

http://www.3drender.com/ 非常好的3D渲染站点,包括多种3D软件教学

http://hjem.get2net.dk/notaw Rhino教学

http://kotanezu.cup.com/ 教你如何做3D汽车的经典指南

http://www.ifrance.com/ 法国的3D制作指南(建模)

http://visualmagic.awn.com/ 全面的3D影象教学、观摩

http://www.max3d.com/ 3DMAX教程、插件大全

http://softimage.ancienfuture.net/ SOFTIMAGE教学网站

http://www.hollywoodfx.com/ 好来坞专业特效

http://www.afionline.org/ 美国电影学院

http://ymqworks.homepage.com/ 3D艺术展示

://www.max3d.com/plugins/download MAX3的PLUG下载总站(100多个)

http://softimage.ancientfuture.net/ SOFTIMAGE的专业站点

http://www.3dluvr.com/fyrenurbs/ 3D技术论坛

软件官方网站:

http://www.aw.sgi.com/ MAYA、ALIAS

http://www.ktx.com/ 3DMAX、3DVIZ

http://www.sidefx.com/ houdini、prisms

http://www.newtek.com/ Lightwave

http://www.formz.com/ formz

http://www.softimage.com/ softimage

http://www.rhino3d.com/ Rhinoceros

http://www.hash.com/ animationmaster

http://www.viewpoint.com/ 全球最大的3D模型站点

http://www.animo.com/ animo

http://www.areteis.com/ SI专业插件制作商

http://www.glasspalace.fi/rhino3d/?

http://www.raph.com/3dartists/

http://www.tyfo.com/tanfoplan/art/ 艺术之旅

http://www.n.com/cgi-bin/ut/board_show.cgi?id=7&age=30 ****设计家园

http://www.flexicad.com/ 犀牛相关

http://www.suurland.com/gallery.htm

http://www.highend3d.com/

http://www.unav.es/cti/manuales/3DStudioMax/indice.html *max相关

http://ericch.myrice.com/tuijie/soft.html **** 工业设计与3D图形欣赏

http://ourworld.topcool.net/top.htm *max相关

http://www.rhino3d.com/tutorials/ *rhinoh帮助

http://www.chinavisual.com/

http://www.tyfo.com/tanfoplan/art/index.htm

http://www.525000.com/lq/club/index.asp

http://www.colorbird.com/

http://www.ergocn.com/index.htm

http://www.design-engine.com/

http://www.eyeonline.com/ 非常漂亮的插件站点

http://www.3dcafe.com/ 最大的三维教学、模型基地

http://www.habware.at/ 3DMAX的免费插件下载

http://www.ping.be/maya MAYA的教学站点

UML类图

在UML的静态机制中类图是一个重点,它不但是设计人员关心的核心,更是实现人员关注的核心。建模工具也主要根据类图来产生代码。类图在UML的9个图中占据了一个相当重要的地位。

James Rumbaugh对类的定义是:类是具有相似结构、行为和关系的一组对象的描述符。类是面向对象系统中最重要的构造块。类图显示了一组类、接口、协作以及他们之间的关系。在UML中问题域最终要被逐步转化,通过类来建模,通过编程语言构建这些类从而实现系统。类加上他们之间的关系就构成了类图,类图中还可以包含接口、包等元素,也可以包括对象、链等实例。接口在类图中通过版型来表示<<interface>>,下面的介绍将主要介绍类,接口和类类似。

A.类的UML表示

类的命名尽量应用领域中的术语,应明确、无岐义,以利于相互交流和理解。类的属性、操作中的可见性使用+、#、-分别表示public、protected、private。

[UML]UML类图

B.类之间的关系

类之间的关系是类图中比较复杂的内容。有关联、聚合、组合、范化、依赖。

关联:是模型元素之间的一种语义联系,是类之间的一种很弱的联系。关联可以有方向,可以是单向关联,也可以是双向关联。可以给关联加上关联名来描述关联的作用。关联两端的类也可以以某种角色参与关联,角色可以具有多重性,表示可以有多少个对象参与关联。可以通过关联类进一步描述关联的属性、操作以及其他信息。关联类通过一条虚线与关联连接。对于关联可以加上一些约束,以加强关联的含义。如下图所示:

[UML]UML类图

聚合是一种特殊的关联,聚合表示整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构。从而找出一些组成类,该整体类和组成类之间就形成了聚合关系。例如舰队是由一系列的舰船组成。需求描述中“包含”、“组成”、“分为….部分”等词常意味着聚合关系。

组合也是一种特殊的关联,也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。部分对象与整体对象之间具有共生死的关系。

聚合和组合的区别:聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

泛化定义了一般元素和特殊元素之间的分类关系,类之间的这种泛化关系也就是继承关系。泛化关系是“a-kind-of”关系,定义一般元素和特殊元素之间的分类关系。下图是一个泛化关系的例子。
 

[UML]UML类图
有两个元素如果修改X的定义可能会导致对Y的定义,则认为Y依赖X。依赖关系可能由各种原因引起,如一个类向另一个类发送消息,或者一个类是另一个类的数据成员类型,或者一个类是另一个类的操作的参数类型等。有时依赖关系和关联关系比较难区分。如果类A和类B有关联关系,它们之间必然有依赖关系。如果两个类之间有关联关系时不用再表示出这两个类之间的依赖关系。

C.建立类图

在软件开发不同阶段使用的类图具有不同的抽象层次,即概念层、说明层、和实现层。使用UML进行应用建模也应该是一个迭代的过程,所以我们应该建立一个类图的层次的概念。

概念层类图描述应用领域中的概念,这些概念与实现它们的类有联系。通常没有直接的映射关系。画概念层类图时很少考虑或不考虑实现问题,因此概念层类图应独立于具体的编程语言。下面是一个概念层类的表示。

[UML]UML类图

说明层类图。此时我们考察的是类的接口部分,而不是实现部分。这个接口可能因为实现环境、运行特性等有多种不同的实现。下面是一个说明层类的表示。

[UML]UML类图

实现层类图才真正考虑类的实现问题,提供实现的细节。此时的类的概念才应该是真正的严格意义上的类。它揭示了软件实体的构成情况。实现层的类是最常用的,在很多的时候说明层的类更有助于人们对软件的理解。

[UML]UML类图

UML的最终目标是识别出所有必须的类,并分析这些类之间的关系,类的识别贯穿于整个建模过程,分析阶段主要识别问题域相关的类,在设计阶段需要加入一些反映设计思想、方法的类以及实现问题域所需要的类,在编码实现阶段,因为语言的特点,可能需要加入一些其他的类。

建立类图的步骤:

(1)研究分析问题领域确定系统需求。

(2)确定类,明确类的含义和职责、确定属性和操作。

(3)确定类之间的关系。

类的识别是一个需要大量技巧的工作,寻找类的一些技巧包括:名词识别法;根据用例描述确定类;使用CRC分析法;根据边界类、控制类、实体类的划分来帮助分析系统中的类;参考设计模式确定类;对领域进行分析或利用已有领域分析结果得到类;利用RUP中如何在分析和设计中寻找类的步骤。

1. 名词识别法:

这种方法的关键是识别系统问题域中的实体。对系统进行描述,描述应该使用问题域中的概念和命名,从系统描述中标识名词及名词短语,其中的名词往往可以标识为对象,复数名词往往可以标识为类。

2. 从用例中识别类:

用例图实质上是一种系统描述的形式,自然可以根据用例描述来识别类。针对各个用例,可以提如下的问题辅助识别:

用例描述中出现了那些实体?

用例的完成需要哪些实体合作?

用例执行过程中会产生并存储哪些信息?

用例要求与之关联的每个角色的输入是什么?

用例反馈与之关联的每个角色的输出是什么?

用例需要操作哪些硬设备?

在面向对象应用中,类之间传递的信息数据要么可以映射到发送方的某些属性,要么该信息数据本身就是一个对象。综合不同的用例识别结果,就可以得到整个系统的类,在类的基础上,我们又可以分析用例的动态特性来对用例进行动态行为建模。

3. 使用CRC分析法:

CRC(Class,Responsibilities,Collaboration)卡的最大价值在于把人们从思考过程模式中脱离出来,更充分的专注于对象技术。CRC卡允许整个项目组对设计做出贡献。参与系统设计的人越多,能够收集到的好主意也就越多。因为CRC会议是大家全力参与的,通常只需要很少的有类名的卡片,实际上没有写出完整的卡片。CRC会议进行中,一些人模拟系统和对象交流,把消息传给其他的对象。通过一步步处理,问题很容易地被解决。它由三部分组成:类(Class)、职责(Responsibility)、协作(Collaborator)。下面是一个CRC卡的示例:

类名
职责1职责1的协作
职责2职责2的协作
…………

职责是类需要知道或做的任何事物。这些职责是类自身所知的知识,或类在执行时所需的知识。协作是指为获取消息,或协助执行活动的其他类。创建CRC模型需要下面的步骤。

1)  建立团队,包括客户、设计人员、分析人员和一个导引者。如果没有那么多人,那么可以是客户和你自己两个人。

2)  找出需求中存在的名词和名词词组,特别注意复数(通常是集合),他们对应的单数才是。把你第一次想到的所有概念都写在白板或纸上。不管看起来这些概念是如何荒谬,把他们都写下来。

3)  筛选。把对象分为三类,核心对象(必须首先实现),可选的(目前不能确定),以及不需要的对象。这之前最好确定一下你的项目范围。某些不属于本项目范围的对象可以使用轻量的adapter或proxy实现。这里可以加入对分析、设计模式的考虑和应用。

4)  建卡。取出CRC卡,把核心类写在每一张卡上,把可选的类和排除的类分别写在不同的纸上。

5)  角色扮演。最好是一个团队执行,一个人很难做。每个人负责几个类。对每一个Use case其中的情景。导引者指定从某一个人的类开始,某一个人看一看自己能够独立完成,如果不能完成,大家看一看手中的类,谁能完成,就站起来,宣布自己能够完成,以致继续这个过程,每个人完成自己的职责就坐下。在这过程中不断修改类的责任,并写下协作者的名字。

4. 根据边界类、控制类、实体类帮助分析系统中的类

UML中类有三种主要的版型:边界类、控制类和实体类。引入边界类、控制类及实体类的概念有助于分析和设计人员确定系统中的类。

边界类位于系统与外界的交界处,窗体、报表、以及表示通讯协议的类、直接与外部设备交互的类、直接与外部系统交互的类等都是边界类。通过用例图可以确定需要的边界类,每个Actor/Use Case对至少要一个边界类,但并非每个Actor/Use Case对要唯一的边界类。

实体类保存要放进持久存储体的信息。持久存储体就是数据库、文件等可以永久存储数据的介质。实体类可以通过事件流和交互图发现。通常每个实体类在数据库中有相应的表,实体类中的属性对应数据库表中的字段。

控制类是控制其他类工作的类。每个用例通常有一个控制类,控制用例中的事件顺序,控制类也可以在多个用例间共用。其他类并不向控制类发送很多消息,而是由控制类发出很多消息。

5. 领域进行分析

建立类图的过程就是对领域及其解决方案的分析和设计过程。类的获取是一个依赖个人创造力的过程,有时需要和领域专家合作,对研究领域进行仔细分析,抽象出领域中的概念,定义其含义及相互关系,分析出系统类,并用领域中的术语为类命名。领域分析是:通过对某一领域中的已有应用系统、理论、技术、开发历史等的研究,来标识、收集、组织、分析和表示领域模型及软件体系结构的过程,并得到结果。

D. 使用类图

类图几乎是所有面向对象方法的支柱,应该如何使用类图呢?以下提供了一些使用类图的一些建议。

不要试图在项目的初始阶段使用所有的符号,首先应该从简单概念开始。比如类的关系等等,在需要的时候才使用。在项目的不同开发阶段,应该使用不同的观点来画类图。如果处于分析阶段应该画概念层类图,当开始着手软件设计时,应该画说明层类图,当针对某个特定的技术实现时应该画实现层类图。不要为每个事物都画一个模型,应该把精力放在关键的领域。使用类图的最大危险是过早的陷入实现的细节,为了避免这个问题,应该将重点放在概念层和说明层。