使用MASM-标号、变量和数据结构(4)

3.3.5  变量的使用

1. 以不同的类型访问变量

这个话题有点像C语言中的数据类型强制转换,C语言中的类型转换指的是把一个变量的内容转换成另外一种类型,转换过程中,数据的内容已经发生了变化,如把浮点数转换成整数后,小数点后的内容就丢失了。在MASM中以不同的类型访问不会对变量造成影响。

举一个简单的例子,先以db方式定义一个缓冲区:

szBuffer    db      1024 dup (?)

然后从其他地方取得了数据,但数据的格式是以字方式组织的,要处理数据,最有效的方法是两个字节两个字节地处理,但如果在程序中把szBuffer的值放入ax

mov     ax,szBuffer

编译器会报一个错:

error A2070: invalid instruction operands

意思是无效的指令操作,为什么呢?因为szBuffer是用db定义的,而ax的尺寸是一个word,等于两个字节,尺寸不符合。MASM中,如果要用指定类型之外的长度访问变量,必须显式地指出要访问的长度,这样,编译器忽略语法上的长度检验,仅使用变量的地址。使用的方法是:

类型 ptr 变量名

类型可以是byteworddwordfwordqwordreal8real10。如:

mov     ax,word ptr szBuffer

mov     eax,dword ptr szBuffer

上述语句能通过编译,当然,类型必须和操作的寄存器长度匹配。在这里要注意的是,指定类型的参数访问并不会去检测长度是否溢出,看下面一段代码:

                .data

bTest1          db      12h

wTest2          dw      1234h

dwTest3         dd      12345678h

               

 

                .code

               

                mov     al,bTest1

                mov     ax,word ptr bTest1

                mov     eax,dword ptr bTest1

               

上面的程序片断,每一句执行后寄存器中的值是什么呢,mov al,bTest1这一句很显然使al等于12h,下面的两句呢,axeax难道等于0012h00000012h吗?实际运行结果很“奇怪”,竟然是3412h78123412h,为什么呢?先来看反汇编的内容:

.data段中的变量

:00403000 12 34 12 78 56 34 12 ...

                   

                    dwTest3

              ────── wTest2

            ─────────    bTest1

 

.code段中的代码

:00401000 A000304000                mov al, byte ptr [00403000]

:00401005 66A100304000          mov ax, word ptr [00403000]

:0040100B A100304000            mov eax, dword ptr [00403000]

.data段中的变量是按顺序从低地址往高地址排列的,对于超过一个字节的数据,80386处理器的数据排列方式是低位数据在低地址,所以wTest21234h在内存中的排列是34h 12h,因为34h是低位。同样,dwTest3在内存中以78h 56h 34h 12h从低地址往高地址存放,在执行指令mov ax,word ptr bTest1的时候,是从bTest1的地址403000h处取一个字,其长度已经超过了bTest1的范围并落到了wTest2中,从内存中看,是取了bTest1的数据12hwTest2的低位34h,在这两个字节中,12h位于低地址,所以ax中的数值是3412h。同样道理,看另一条指令:

mov     eax,dword ptr bTest1

这条指令取了bTest1wTest2的全部和dwTest3的最低位78h,在内存中的排列是12h  34h 12h 78h,所以eax等于78123412h

这个例子说明了汇编中用ptr强制覆盖变量长度的时候,实质上是只用了变量的地址而禁止编译器进行检验,编译器并不会考虑定界的问题,程序员在使用的时候必须对内存中的数据排列有个全局概念,以免越界存取到意料之外的数据。

如果程序员的本意是类似于C语言的强制类型转换,想把bTest1的一个字节扩展到一个字或一个双字再放到axeax中,高位保持0而不是越界存取到其他的变量,可以用80386的扩展指令来实现。80386处理器提供的movzx指令可以实现这个功能,例如:

movzx       ax,bTest1          ;例1

movzx       eax,bTest1         ;例2

movzx       eax,cl             ;例3

movzx       eax,ax             ;例4

   1把单字节变量bTest1的值扩展到16位放入ax中。

   2把单字节变量bTest1的值扩展到32位放入eax中。

   3cl中的8位值扩展到32位放入eax中。

   4ax中的16位值扩展到32位放入eax中。

movzx指令进行数据长度扩展是Win32汇编中经常用到的技巧。

2. 变量的尺寸和数量

在源程序中用到变量的尺寸和数量的时候,可以用sizeoflengthof伪指令来实现,格式是:

sizeof            变量名、数据类型或数据结构名

lengthof          变量名、数据类型或数据结构名

sizeof伪指令可以取得变量、数据类型或数据结构以字节为单位的长度,lengthof可以取得变量中数据的项数。假如定义了以下数据:

stWndClass     WNDCLASS     <>

szHello        db           'Hello,world!',0

dwTest         dd           1,2,3,4

              

               .code

              

               mov          eax,sizeof stWndClass

               mov          ebx,sizeof WNDCLASS

               mov          ecx,sizeof szHello

               mov          edx,sizeof dword

               mov          esi,sizeof dwTest

执行后eax的值是stWndClass结构的长度40ebx同样是40ecx的值是13,就是“Hello,world!”字符串的长度加上一个字节的0结束符,edx的值是一个双字的长度:4,而esi则等于4个双字的长度16

如果把所有的sizeof换成lengthof,那么eax会等于1,因为只定义了1WNDCLASS,而ecx同样等于13esi则等于4,而lengthof WNDCLASSlengthof dword是非法的用法,编译程序会报错。

要注意的是,sizeoflengthof的数值是编译时候产生的,由编译器传递到指令中去,上边的指令最后产生的代码就是:

mov        eax,40

mov        ebx,40

mov        ecx,13

mov        edx,4

mov        esi,16

 如果为了把HelloWorld分两行定义,szHello是这样定义的:

szHello       db      'Hello',0dh,0ah

              db      'World',0

那么sizeof szHello是多少呢?注意!是7而不是13MASM中的变量定义只认一行,后一行db 'World',0实际上是另一个没有名称的数据定义,编译器认为sizeof szHello是第一行字符的数量。虽然把szHello的地址当参数传给MessageBox等函数显示时会把两行都显示出来,但严格地说这是越界使用变量。虽然在实际的应用中这样定义长字符串的用法很普遍,因为如果要显示一屏幕帮助,一行是不够的,但要注意的是:要用到这种字符串的长度时,千万不要用sizeof去表示,最好是在程序中用lstrlen函数去计算。



来源:电子工业出版社 作者:罗云彬
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
-------------------------- 我是汇编爱好者 QQ695367480 高手别找我了 我是菜鸟。 -------------------------- 内容简介: Windows环境下32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以用来开发出大型的软件,而且是了解操作系统运行细节的最佳方式。本书从编写应用程序的角度,从“Hello World!”这个简单的例子开始到编写多线程、注册表和网络通信等复杂的程序,通过60多个实例逐渐深入Win32汇编语言的方方面面。本书作者罗云彬拥有十余年汇编语言编程经验,是汇编编程网站http://asm.yeah.net和汇编编程论坛http://win32asm.yeah.net的站长。本书是作者多年来编程工作的总结,适合于欲通过Win32汇编语言编写Windows程序的读者。 第1章 背景知识 1.1 Win32的软硬件平台(1) 1.1 Win32的软硬件平台(2) 1.2 Windows的特色 1.3 必须了解的东西(1) 1.3 必须了解的东西(2) 1.3 必须了解的东西(3) 1.3 必须了解的东西(4) 1.3 必须了解的东西(5) 第2章 准备编程环境 2.1 Win32可执行文件的开发过程 2.2 编译器和链接器(1) 2.2 编译器和链接器(2) 2.2 编译器和链接器(3) 2.3 创 建 资 源 2.4 make工具的用法(1) 2.4 make工具的用法(2) 2.5 获 取 资 料 2.6 构建编程环境 第3章 使用MASM 当搭建编译和对编译器使用不再成为绊脚石的时候,初学者的问题往往集中在对Windows程序结构的迷惑上,消息驱动体系、窗口过程、与硬件隔绝的图形接口及资源文件等相对于DOS程序来说都是全新的内容,接下来的4章将深入讨论这些内容,通过这几章,读者应该开始习惯以Windows的方式考虑问题了(脑海中的DOS逐渐远去...),这就是本书的初级篇: 3.1 Win32汇编源程序的结构(1) 3.1 Win32汇编源程序的结构(2) 3.1 Win32汇编源程序的结构(3) 3.2 调用API(1) 3.2 调用API(2) 3.2 调用API(3) 3.3 标号变量数据结构(1) 3.3 标号变量数据结构(2) 3.3 标号变量数据结构(3) 3.3 标号变量数据结构(4) 3.3 标号变量数据结构(5) 3.4 使用子程序 3.5 高 级 语 法(1) 3.5 高 级 语 法(2) 3.6 代 码 风 格(1) 3.6 代 码 风 格(2) 第4章 第一个窗口程序 4.1 开始了解窗口(1) 4.1 开始了解窗口(2) 4.1 开始了解窗口(3) 4.2 分析窗口程序(1) 4.2 分析窗口程序(2) 4.2 分析窗口程序(3) 4.2 分析窗口程序(4) 4.2 分析窗口程序(5) 4.3 窗口间的消息互发 4.4 实 验(1) 4.4 实 验(2) 4.4 实 验(3) 第5章 使用资源 5.1 菜单和加速键(1) 5.1 菜单和加速键(2) 5.1 菜单和加速键(3) 5.1 菜单和加速键(4) 5.1 菜单和加速键(5) 5.1 菜单和加速键(6) 5.1 菜单和加速键(7) 5.2 图标和光标(1) 5.2 图标和光标(2) 5.3 位 图 5.4 对 话 框(1) 5.4 对 话 框(2) 5.4 对 话 框(3) 5.4 对 话 框(4) 5.4 对 话 框(5) 5.4 对 话 框(6) 5.4 对 话 框(7) 5.4 对 话 框(8) 5.4 对 话 框(9) 5.4 对 话 框(10) 5.4 对 话 框(11) 5.5 字符串资源/5.6 版本信息资源(1) 5.6 版本信息资源(2) 5.7 二进制资源和自定义资源 第6章 定时器 6.1 定时器简介/6.2 定时器的使用(1) 6.2 定时器的使用(2) 6.3 取Windows时间 第7章 图形操作 Windows系统不像DOS系统,它的应用程序界面是规范化的,统一的界面来自大量的系统界面控件,学习这些控件就等于学习如何编写Windows界面,下面的界面篇中的两章将探讨这方面的内容: 7.1 GDI原理(1) 7.1 GDI原理(2) 7.1 GDI原理(3) 7

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪宁宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值