现在的位置: 首页 > 综合 > 正文

关于宏

2013年08月05日 ⁄ 综合 ⁄ 共 2195字 ⁄ 字号 评论关闭

我在学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))

这些就是关于宏的一些知识

参考《删繁就简——单片机入门到精通》

每天都进步一点鄙视

抱歉!评论已关闭.