看到一个“宏定义学习手记”的帖子,很多人,不管懂还是不懂都帮顶,自己有点感想,所以把想法说出来,让大家来讨论。[只对汇编语言]
宏,简单来说,可以理解成替换,代表的意思。比如 M_InitTime0 EQU 20H,可以理解成20H可用M_InitTime0来替换,或者说M_InitTime0就是代表20H。同样的道理,也可以把一段代码定义成一个宏,用这个宏来代替这段代码。在编译的时候,如果遇到M_InitTime0就用20H来替换,如果遇到宏函数,就用那段代码来替换宏。
问过许多人,为什么喜欢用宏?大多数的回答是说:很方便。大部分人的答案第一句就是这个了,具体的再问,就各有各的想法了。主要有2点:
1、定义常量很方便,比如程序中有个数值115864,看程序的人也许不知道什么意思,但是如果宏定义System_Clock EQU 115864,然后程序中看到System_Clock就知道什么意思,还有其他定义方便就不说了。
2、宏函数调用,带参数很方便。因为汇编语言中,子函数带参数,用起来有点“丑”,而且如果是多个参数的话要用到堆栈,用起来更“丑”,涉及到压栈,程序就有跑飞危险!对于高手来说,主要的还是方便调用,确实,宏函数调用最多一行,挺漂亮的。
宏虽然用起来很方便,但是,宏最好也别滥用和乱用。用了宏,程序的行数确实少了,但是不要以为是程序精短了哦,相反的,宏函数用得越多,程序的质量越差,代码空间浪费的也多。为什么呢?因为,宏函数是替换,而不是跳转地址!跟子函数的原理不一样,宏函数是一段程序代替宏名的位置,子函数是跳转到指定地址。比如:
TCCA_SETUP MACRO TCCACNT
clr 0x04 ; 0x04 是用来做临时寄存器用的
ior 0x08 ; 0x08是控制TCCA的寄存器
and a,@0xf8 ; 屏蔽掉TCCA相关的
mov 0x04,a
mov a,@TCCACNT ; 读取传递进来的参数
or a,0x04
iow 0x08
mov a,@TCCACNT ; 如果允许TCCA的话,开TCCA的中断
and a,@0x04 ; 否则直接跳出
jbc 0x03,2
jmp $+4
ior 0x0f
or a,@0x08
iow 0x0f
ENDM
拿这个宏来说吧,调用的时候,宏里面的代码会替代宏名TCCA_SETUP出现的地方,当然这里只做初始化还没什么,但是如果调用上了10次呢,按照这个来说,就会比子函数方式多出14*10条指令!
所以宏并不是什么都好,用宏的时候要特别留心了。
1、不能什么都用宏定义,最起码要有代表性!因为你是宏的作者,你会自认为对你来说很方便,也肯定容易看得明白!但是,对别人来说就是一种折磨了,想想看,如果一个工程里有几百个“你认为很方便的”宏定义常量,别人看到的也许是头大。
2、一定要写注释!这个就什么好说的了。
3、精短的,不复杂的,常用到的,可以写成宏函数。但是,不推荐长的,算法复杂的,常用的宏函数,书上也是这样推荐的!
初学者有一种趋势,喜欢用宏定义,那时因为上面的方便。高手也许常量宏定义多,但是宏函数估计不多。当然,对于宏函数中调用子函数的方法,本人是推荐的,因为它跟子函数调用的原理一样,只是美化了而已。
我声明,我不是高手,反而是那种喜欢研究程序结构,程序算法,程序质量,精简程序的人。因为宏的使用,如果滥用乱用,会对阅读造成影响,会对程序精简造成影响,故此提出,望高手能改变我的想法。 |