变量和函数的命名(匈牙利命名法)
规则:匈牙利表示法用连在一起的几个部分来命名一个变量,格式是类型前缀加上变量说明。
类型用小写字母表示,如用h表示句柄,用dw表示double word,用sz表示以0结尾的字符串等,说明则用首字母大写的几个英文单词组成,如TimeCounter,NextPoint等,可以令人一眼看出变量的含义来。
在汇编语言中常用字的类型前缀有:
b 表示byte
w 表示word
dw 表示dword
h 表示句柄
lp 表示指针
sz 表示以0结尾的字符串
lpsz 表示指向以0结尾的字符串的指针
f 表示浮点数
st 表示一个数据结构
这样一来,变量的意思就很好理解:
hWinMain 主窗口的句柄
dwTimeCount 时间计数器,以双字定义
szWelcome 欢迎信息字符串,以0结尾
lpBuffer 指向缓冲区的指针
很明显,这些变量名比cangjingkong,xiaojiayu之类的命名要易于理解。由于匈牙利表示法既描述了变量的类型,又描述了变量的作用,所以能帮助程序员及早发现变量的使用错误。
对于函数名,由于不会返回多种类型的数值,所以命名时一般不再用类型开头,但名称还是用表示用途的单词组成,每个单词的首字母大写。
Windows API是这种命名方式的绝好例子,当人们看到ShowWindow,GetWindowText,DeleteFile 和 GetCommandLine 之类的API函数名称时,恐怕不用查手册,就能知道它们是做什么用的。
比起int 21h/09h和int 13h/02h之类的中断调用,好处是不必多讲的。
由于汇编语言有语法上的特殊性,所以我们命名的时候应该考虑下面这些汇编语言特有的问题:
对局部变量的地址引用要用lea指令或用addr伪操作,全局变量要用offset;对局部变量的使用要特别注意初始化问题。那么我的命名应该尽量区分,如何在定义中区分全局变量、局部变量和参数?
汇编的源代码占用的行数比较多,代码行数很容易膨胀,程序规模大了如何分清一个函数是系统的API还是本程序内部的子程序?
实际上上面的这些问题可以归纳为区分作用域的问题。为了分清变量的作用域,命名中对全局变量、局部变量和参数应该有所区别,所以我们需要对匈牙利表示法做一些补充。
全局变量的定义使用标准的匈牙利表示法,在参数的前面加下划线,在局部变量的前面加@符号,这样引用的时候就能随时注意到变量的作用域。
在内部子程序的名称前面加下划线,以便和系统API区别。
代码的书写格式
排版方式:程序的排版风格应该遵循以下规则。
首先是大小写的问题,汇编程序中对于指令和寄存器的书写是不分大小写的,但小写代码比大写代码便于阅读,所以程序中的指令和寄存器等要采用小写字母,而用equ伪操作符定义的常量则使用大写,变量和标号使用匈牙利表示法,大小写混合。
其次是使用Tab的问题。汇编源程序中Tab的宽度一般设置为8个字符。在语法上,指令和操作数之间至少有一个空格就可以了,但指令的助记符长度是不等长的。
用Tab隔开指令和操作数可以使格式对齐,便于阅读:
xor eax,eax
fistp dwNumber
xchg eax,ebx
上述代码的写法就不如下面的写法整齐:
xor eax,eax
fistp dwNumber
xchg eax,ebx
.data
dwFlag dd ?
.code
start:
mov eax,dwFlag
.if dwFlag == 1
call _Function1
.else
call _Function2
.endif
合适的缩进格式可以明显地表现出程序的流程结构,也很容易发现嵌套错误。
注释和空行
没有注释的程序是很难维护的,但注释的方法也很有讲究,写注释要遵循以下的规则:
不要写无意义的注释。
修改代码同时修改相应的注释。
注释以描写一组指令实现的功能为主,不要解释单个指令的用法,那是应该由指令手册来完成的,不要假设看程序的人连指令都不熟悉。
对于子程序,要在头部加注释说明参数和返回值,子程序可以实现的功能,以及调用时应该注意的事项。
由于汇编语言是以一条指令为一行的,实现一个小功能就需要好几行,没有分段的程序很难看出功能模块来。
所以要合理利用空行来隔开不同的功能块,一般以在高级语言中可以用一句语句来完成的一段汇编指令为单位插入一个空行。
宏的使用原则
在汇编中避免使用宏定义的理由是:
破坏本来就不和谐的可读性。
汇编中随时要用到各个寄存器,宏定义不同于子程序,可以有选择地保护现场,在使用中很容易忽略里面用了哪个寄存器,从而对程序结构构成威胁。
高级语言的宏定义则不会有这个问题,所以在汇编中我们还是不提倡使用宏,出了条件汇编。
代码的组织
程序中要注意变量的组织和模块的组织方式。
过多的全局变量会影响程序的模块化结构,所以不要设置没必要的全局变量,尽量把变量定义成局部变量(符合封装的思想)。
把仅在子程序中使用的变量设置为局部变量可以使子程序更容易封装成一个黑匣子,如果无法把全部变量设置为局部变量,则尽量把这些数据改为参数输入输出,如果无法改为参数,那么意味着这个子程序不能不经修改地直接放到别的程序中使用。
在主程序中使用比较频繁的部分,以及便于封装成黑匣子在别的程序上用的代码,都应该写上子程序。
但一个子程序的规模不应该太大,行数尽量限制在几百行之内,功能则限于完成单个功能。
对于子程序,定义参数的时候要尽可能精简,对可能引起程序崩溃的参数,如指针等,要进行合法性检测。
子程序中在使用完申请的资源的时候,注意在退出前要释放所用资源,包括申请的内存和其他句柄等,对于打开的文件则要关闭。
对于程序员来说,开发每一个软件都是要从头做起是很浪费时间的,一般的做是从自己以前做的程序中拷贝相似的代码,但修改还是要花一定时间。
最好的办法就是尽量把子程序做成一个黑匣子,可以不经修改地直接拿过来用(后边我们的程序都是这么弄滴)。
这样,每次编程相当于只是编写新增的部分,随着代码的积累,开发任何程序都将是很快的事情(也是愉快的过程)。