使用MASM-代码风格(1)

随着程序功能的增加和版本的提高,程序越来越复杂,源文件也越来越多,风格规范的源程序会对软件的升级、修改和维护带来极大的方便,要想开发一个成熟的软件产品,必须在编写源程序的时候就有条不紊,细致严谨。

在编程中,在程序排版、注释、命名和可读性等问题上都有一定的规范,虽然编写可读性良好的代码并不是必然的要求(世界上还有难懂代码比赛,看谁的代码最不好读懂!),但好的代码风格实际上是为自己将来维护和使用这些代码节省时间。本节就是对汇编语言代码风格的建议。

3.6.1  变量和函数的命名

1. 匈牙利表示法

匈牙利表示法主要用在变量和子程序的命名,这是现在大部分程序员都在使用的命名约定。“匈牙利表示法”这个奇怪的名字是为了纪念匈牙利籍的Microsoft程序员Charles Simonyi,他首先使用了这种命名方法。

匈牙利表示法用连在一起的几个部分来命名一个变量,格式是类型前缀加上变量说明,类型用小写字母表示,如用h表示句柄,用dw表示double word,用sz表示以0结尾的字符串等,说明则用首字母大写的几个英文单词组成,如TimeCounterNextPoint等,可以令人一眼看出变量的含义来,在汇编语言中常用的类型前缀有:

b           表示byte

w           表示word

dw          表示dword

h           表示句柄

lp          表示指针

sz          表示以0结尾的字符串

lpsz            表示指向0结尾的字符串的指针

f           表示浮点数

st          表示一个数据结构

这样一来,变量的意思就很好理解:

hWinMain            主窗口的句柄

dwTimeCount     时间计数器,以双字定义

szWelcome       欢迎信息字符串,以0结尾

lpBuffer            指向缓冲区的指针

stWndClass      WNDCLASS结构

很明显,这些变量名比count1abccommandlinebufferFILEFLAG之类的命名要易于理解。由于匈牙利表示法既描述了变量的类型,又描述了变量的作用,所以能帮助程序员及早发现变量的使用错误,如把一个数值当指针来使用引发的内存页错误等。

对于函数名,由于不会返回多种类型的数值,所以命名时一般不再用类型开头,但名称还是用表示用途的单词组成,每个单词的首字母大写。Windows API是这种命名方式的绝好例子,当人们看到ShowWindowGetWindowTextDeleteFileGetCommandLine之类的API函数名称时,恐怕不用查手册,就能知道它们是做什么用的。比起int 21h/09hint 13h/02h之类的中断调用,好处是不必多讲的。

2. 对匈牙利表示法的补充

使用匈牙利表示法已经基本上解决了命名的可读性问题,但相对于其他高级语言,汇编语言有语法上的特殊性,考虑下面这些汇编语言特有的问题:

   对局部变量的地址引用要用lea指令或用addr伪操作,全局变量要用offset;对局部变量的使用要特别注意初始化问题。如何在定义中区分全局变量、局部变量和参数?

   汇编的源代码占用的行数比较多,代码行数很容易膨胀,程序规模大了如何分清一个函数是系统的API还是本程序内部的子程序?

实际上上面的这些问题都可以归纳为区分作用域的问题。为了分清变量的作用域,命名中对全局变量、局部变量和参数应该有所区别,所以我们需要对匈牙利表示法做一些补充,以适应Win32汇编的特殊情况,下面的补充方法是笔者提出的,读者可以参考使用:

   全局变量的定义使用标准的匈牙利表示法,在参数的前面加下划线,在局部变量的前面加@符号,这样引用的时候就能随时注意到变量的作用域。

   在内部子程序的名称前面加下划线,以便和系统API区别。

如下面是一个求复数模的子程序,子程序名前面加下划线表示这是本程序内部模块,两个参数——复数的实部和虚部用_dwX_dwY表示,中间用到的局部变量@dwResult则用@号开头:

_Calc       proc     _dwX,_dwY

            local    @dwResult

 

            finit

            fild     _dwX

            fld      st(0)

            fmul        ;i * i

            fild     _dwY

            fld      st(0)

            fmul        ;j * j

            fadd        ;i * i + j * j

            fsqrt       ;sqrt(i * i + j * j)

            fistp    @dwResult  ;put result

            mov      eax,@dwResult

            ret

 

_Calc                   endp       

本书中所有的示范源代码采用的都是这样的命名约定。

3.6.2  代码的书写格式

1. 排版方式

程序的排版风格应该遵循以下规则。

首先是大小写的问题,汇编程序中对于指令和寄存器的书写是不分大小写的,但小写代码比大写代码便于阅读,所以程序中的指令和寄存器等要采用小写字母,而用equ伪操作符定义的常量则使用大写,变量和标号使用匈牙利表示法,大小写混合。

其次是使用Tab的问题。汇编源程序中Tab的宽度一般设置为8个字符。在语法上,指令和操作数之间至少有一个空格就可以了,但指令的助记符长度是不等长的,用Tab隔开指令和操作数可以使格式对齐,便于阅读。如:

    xor eax,eax

    fistp dwNumber

    xchg eax,ebx

上述代码的写法就不如下面的写法整齐:

    xor         eax,eax

    fistp       dwNumber

    xchg    eax,        ebx

还有就是缩进格式的问题。程序中的各部分采用不同的缩进,一般变量和标号的定义不缩进,指令用两个Tab缩进,遇到分支或循环伪指令再缩进一格,如:

                .data

dwFlag      dd  ?

                .code

start:

                mov     eax,dwFlag

                .if     dwFlag == 1

                        call        _Function1

                .else

                        call        _Function2

                .endif

           

合适的缩进格式可以明显地表现出程序的流程结构,也很容易发现嵌套错误,当缩进过多的时候,可以意识到嵌套过深,该改进程序结构了。



来源:电子工业出版社 作者:罗云彬

你可能感兴趣的:(数据结构,api,汇编,function,Microsoft,语言)