我在学C语言的时候是知道有宏这个东西的,但当时并没有把它放在心上。直到后来接触单片机时,才渐渐发现了宏的威力。
关于宏,有一下几点需要说明。
1.宏的书写需要用大写
这不是硬性要求,但是是一个通用的准则。这是为了和变量,函数等声明区分开来。算是使用宏的第一准则(我刚开始根本不知道这些)
2.程序中的各种定义尽量用宏
比如写单片机程序,我们经常将跟硬件有关的定义写成宏。比如 #define LED P3。这样是为了以后当换硬件平台时,方便移植与修改,只需要将宏后面的代表项改变就是了。还有常常用到宏的地方就是一些常量。比如一个测试值的最大值只能到200,程序中我们会经常用到这个值与之比较。那么就可以定义宏 #define MAX 200。这样如果方便程序修改,同时也使代码更加清晰了不少。
3.防止头文件被包含
开始学写自己的头文件的时候,我根本不知道有这些。所以,当信心满满的写好自己的头文件加到工程中编译链接,结果出现了重复定义的错误。后来上网才知道是因为头文件的重复包含导致。于是学会了用宏进行处理。处理过程很简单,只需要在所写头文件中写下如下代码
#ifndef _MYHEADER_H #define _MYHEADER_H //头文件内容 #endif (_MYHEADER_H)
其中括号中为可选项。就这么简单。
4.使用宏定义表达式需要使用完备的括号防止出错
当在宏定义中需要用到运算表达式时,最好给每个参数都加上括号。注意,是每个。下面就是一个例子:
#define SQUARE(x) (x*x)
依照这种宏定义的话那么SQUARE(1+2) = 1+2*1+2 = 5 。结果就为5,而不是我们想要的9
所以正确的宏定义为
#define SQUARE(x) ((x)*(x))
这样把每个参数都包含起来,就不会出错了。
5.使用宏时不允许参数发生变化
#define SQUARE((x)*(x))
int a = 2;
int b;
b = SQUARE(a++); //SQUARE(a++) = (a++)*(a++),结果执行了两次加一操作,结果为4
正确的操作应该是:
b = SQUARE(a);
a++; //只执行一次累加结果为3
6.使用宏定义的表达式应放在大括号中
就像这样:
#defined INIT_VALUE(x,y)\
{\
x=0;\
y=0;\
}
"\"表示下一行继续为宏定义的内容
7.将常用数据类型重新定义,方便由于平台不同而产生的类型字节数差异,方便移植。
这个是很有用的,所以我们经常会看到有些单片机的模版文件中有一个配置头文件"config.h"这里面就包含了常用数据的定义。如果当平台更换时,如果数据类型不同,我们则只需修改宏就是了,很方便。
8.使用宏进行跟踪调试
#define DEBUGMSG(msg)\
{\
#ifdef _DEBUG_\
printf(msg);\
#endif\
}
主要是为了程序的连续调试。
下面展示了是一些实用的宏实例
//求最大值和最小值 #define MAX(x,y) (((x)>(y))? (x):(y)) #define MIN(x,y) (((x)<(y))? (x):(y)) //高低字节操作,类型为自定义类型 #define HI_BYTE(n) (UINT8)((n>>8)&0xFF) #define LO_BYTE(n) (UINT8)(n&0xFF) #define BYTE2WORD(hi,lo) (UINT16)((hi<<8)|lo) //高低字操作,类型为自定义类型 #define HI_WORD(n) (UINT16)((n>>16)&0x0FFFF) #define LO_WORD(n) (UINT16)(n&0x0FFFF) #define WORD2DWORD(hi,lo) (UINT32)(((UINT32)hi << 16)|lo) //读、写指定地址上的字节 #define MEM_BYTE(x) (*((UINT8 *)(x))) //字母大小写转换 #define UPCASE(c) (((c)>='a'&&(c)<='z')? ((c)-0x20):(c)) #define LOWCASE(c) (((c)>='A'&&(c)<='Z')? ((c)+0x20):(c)) //十进制和BCD转换 #define BCD_TO_DEC(bcd) ((((UINT8)(bcd))>>4)*10 + (((UINT8)(bcd))&0x0f))) #define DEC_TO_BCD(dec) ((((((UINT8)(dec))/10)<<4)|((UINT8)(dec))%10)) //返回数组元素的个数 #define ARR_SIZE(a) (sizeof((a))/sizeof((a[0]))) //位操作 #define TEST_BIT(x,offset) (1&((x)>>offset))) #define SET_BIT(x,offset) ((x)|=(1<<offset))) #define CLR_BIT(x,offset) ((x)&=(~(1<<(offset)))) //面试常问的用宏表示一年有多少时间(留意溢出) #define MINS_OF_YEAR ((UINT32)(365*24*60)) #define SECS_OF_YEAR ((UINT32)(365*24*60*60))
这些就是关于宏的一些知识
参考《删繁就简——单片机入门到精通》
每天都进步一点