如何有效的组织数据,以及相关的编程技术
描述了单元长度的标号
在代码段中经常使用标号来标记指令、数据、段的起始地址
1 | assume cs:code |
a、b这些标号仅仅表示了内存单元的地址
另一种标号,不但可以表示内存单元的地址,还可表示内存单元的长度,即表示在此标号处的单元,是字节单元还是字单元,或者双字单元
1 | assume cs:code |
a或者b是同时描述内存地址和单元长度的标号
标号a,描述了地址code:0,而且从这个地址开始,以后的内存单元都是字节单元
标号b,描述了地址code:8,而且从这个地址开始,以后的内存单元都是字单元
这种标号包含了对单元长度的描述,所以在指令中,此种标号可以代表一个段中的内存单元
例:b dw 0
指令:
mov ax,b相当于:
mov ax,cs:[8]指令:
mov b,2相当于:
mov word ptr cs:[8],2指令:
mov al,b会引起编译错误,因为b代表的内存单元是字单元,而al是8位寄存器
例:a db 1,2,3,4,5,6,7,8
指令:
mov al,a[si]相当于:
mov al,cs:0[si]
这种标号称为数据标号,它标记了存储数据的单元的地址和长度,不同于仅表示地址的地址标号
在其他段中使用的数据标号
一般来说,不再代码段中定义数据,而是将数据定义到其他段中
在其他段中,也可以使用数据标号来描述存储数据的单元的地址和长度
注意:在后面加有“:”的地址标号,只能在代码段中使用,不能在其他段中使用
例:将data段中a标号处的8个数据累加,结果存储到b标号处的字中
1 | assume cs:code,ds:data |
若在代码段中直接使用数据标号访问数据,则需使用伪指令assume将标号所在的段和一个段寄存器联系起来,否则在编译器编译的时候,无法确定标号的段地址在哪一个寄存器中(ds:data)
但并不是用assume指令将段寄存器和某个段相联系后,段寄存器就会真的存放该段的地址,而要在程序中使用指令对段寄存器进行设置(mov ax,data、mov ds,ax)
将标号当作数据来定义
可以将标号当作数据来定义,此时,编译器将标号所表示的地址当作数据的值
例:
1 | data segment |
数据标号c处存储了两个字型数据,为标号a、b的偏移地址。相当于:
1 | data segment |
例:
1 | data segment |
数据标号c处存储了两个双字型数据,为标号a的偏移地址和段地址、标号b的偏移地址和段地址。相当于:
1 | data segment |
seg操作符,功能为取得某一标号的段地址
直接定址表
用查表的方法编写相关程序的技巧
编写子程序,用十六进制的形式在屏幕中间显示给定的字节型数据
分析:
一个字节,在寄存器中以8位二进制方式存储,首先转换为其十六进制,然后将这个十六进制显示在屏幕上
一个字节需两个十六进制数码来表示(一个字节为8位二进制,一个十六进制表示4位二进制),所以,子程序须在屏幕上显示两个ASCII字符,使用0--F来显示十六进制数码
可将一个字节的高4位和低4位分开,分别用它们的值得到对应的数码字符
希望能够在数值0–15和字符0--F之间找到一种映射关系
但数值0–9和字符0--9之间的映射关系是:数值+30h=对应字符的ASCII值
数值10–15和字符A--F之间的映射关系是:数值+37h=对应字符的ASCII值
具体做法是:建立一张表,表中依次存储字符0--F,通过数值0–15直接查找到对应的字符
1 | ;用al传送要显示的数据 |
在子程序中,在数值0–15和字符0--F之间建立的映射关系为:以数值N为table表中的偏移,可以找到对应的字符
利用表,在两个数据集合之间建立一种映射关系,使得可以使用查表的方法根据给出的数据得到其在另一集合中的对应数据。这么做的目的有:
为了算法的清晰和简洁
为了加快运算速度
为了使程序易于扩充
编写一个子程序,计算sin(x),xϵ{0°,30°,60°,90°,120°,150°,180°},并在屏幕中间显示计算结果
若使用麦克劳林公式进行计算,其中涉及多次乘法和除法。乘除是非常费时的运算,执行的时间大约是加法、比较等指令的5倍
可以使用一些存储空间换取运算的速度,将计算的sin(x)的结果存储到一张表中,然后用角度值来查表,找到对应的sin(x)的值
1 | ;用ax向子程序传递角度 |
子程序中,在角度值X和表示sin(x)的字符串集合table之间建立的映射关系为:以角度/30为table表中的偏移,可以找到对应的字符串的首地址
通过将给出的数据进行计算或比较而得到结果的问题,转化为用给出的数据作为查表的依据,通过查表得到结果的问题
具体的查表的方法,是用查表的依据数据,直接计算出所要查找的元素在表中的位置
像这种可以通过依据数据,直接计算出所要找的元素的位置的表,称为直接定址表
程序入口地址的直接定址表
可以直接在直接定址表中存储子程序的地址,方便的实现不同子程序的调用
实现一个子程序setscreen,为显示输出提供如下功能
清屏
设置前景色
设置背景色
向上滚动一行
入口参数:
ah寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行对于2,3号功能,用
al传送颜色值,(al)ϵ{0,1,2,3,4,5,6,7}
功能实现:
清屏:将显存中当前屏幕中的字符设为空格符
设置前景色:设置显存中当前屏幕中处于奇地址的属性字节的第0、1、2位
设置背景色:设置显存中当前屏幕中处于奇地址的属性字节的第4、5、6位
向上滚动一行:依次将第
n+1行的内容复制到第n行;最后一行为空
1 | ;清屏 |
将这些功能子程序的入口地址存储在一个表中,它们在表中的位置和功能号相对应。对应关系为:功能号*2=对应的功能子程序在地址表中的偏移
1 | setscreen:jmp short set |