用好C语言的宏定义可以让代码更加简洁漂亮。宏定义有更好的可读性、增加可移植性、方便编写代码等优点。接下来向大家介绍常用宏定义的几种用法。
1. 防止头文件重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2. 重新定义类型
重新定义类型,避免在不同平台和编译器上,类型的字节不同,因而出bug,方便代码的移植。
typedef unsigned char boolean; /* 布尔类型 */
typedef unsigned long int uint64; /* 无符号64位类型 */
typedef unsigned int uint32; /* 无符号32位类型 */
typedef unsigned short uint16; /* 无符号16位类型 */
typedef unsigned char uint8; /* 无符号8位类型 */
typedef signed long int uint64; /* 64位类型 */
typedef signed int int32; /* 32位类型 */
typedef signed short int16; /* 16位类型 */
typedef signed char int8; /* 8位类型 */
或者是下面这样:
typedef unsigned char byte; /* 无符号8位类型 */
typedef unsigned short word; /* 无符号16位类型 */
typedef unsigned int dword; /* 无符号32位类型 */
typedef unsigned char uint1; /* 无符号8位类型 */
typedef unsigned short uint2; /* 无符号16位类型 */
typedef unsigned int uint4; /* 无符号32位类型 */
typedef unsigned long uint8; /* 无符号64位类型 */
typedef signed char int1; /* 8位类型 */
typedef signed short int2; /* 16位类型 */
typedef signed int int4; /* 32位类型 */
typedef signed int int8; /* 64位类型 */
typedef signed int sint63; /* 64位类型 */
typedef signed int sint31; /* 32位类型 */
typedef signed short sint15; /* 16位类型 */
typedef signed char sint7; /* 8位类型 */
3. 得到指定地址上的一个字节或字
#define MEM_B(x) (*((byte*) x))
#define MEM_W(x) (*((word*) x))
4. 求最大值和最小值
#define MAX(x, y) (((x) > (y))? (x):(y))
#define MIN(x, y) (((x) < (y))? (x):(y))
5. 得到一个field在结构体(struct)中的偏移量
#define FPOS(type, field) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6. 得到一个结构体中field所占用的字节数
#define FSIZ(type, field) (sizeof(((type*) 0) -> field))
7. 按照LSB格式把两个字节转化为一个Word
#define FLIPW(ray) ((((word) (ray)[0]) * 256) + (ray)[1])
8. 按照LSB格式把一个Word转化为两个字节
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9. 得到一个变量的地址(word宽度)
#define B_PTR(var) ((byte*)(void*) & (var))
#define W_PTR(var) ((word*)(void*) & (var))
10. 得到一个字的高位和低位字节
#define WORD_LO(xxx) ((byte)((word)xxx) & 255)
#define WORD_HI(xxx) ((byte)((word)xxx) >> 8)
11. 返回一个比X大的最接近的8的倍数
#define RND8(x) ((((x) + 7) / 8) * 8)
12. 将一个字母转换为大写
#define UPCASE(c) (((c) >= 'a' && (c) <= 'z')? ((c) - 0x20): (c))
13. 判断字符是不是10进制的数字
#define DECCHK(c) ((c) >= '0' && (c) <= '9')
14. 判断字符是不是16进制的数字
#define HEXCHK(c) (((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f'))
15. 防止溢出的一个方法
#define INC_SAT(val) (val = ((val)+1 > (val))? (val)+1: (val))
16. 返回数组元素的个数
#define ARR_SIZE(a) ( sizeof((a)) / sizeof((a[0]))
17. 返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO(val, mod_by) \
((dword)(val) & (dword)((mod_by)-1))
18. 对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port) (*((volatile byte*) (port)))
#define inpw(port) (*((volatile word*) (port)))
#define inpdw(port) (*((volatile dword*)(port)))
#define outp(port, val) (*((volatile byte*) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word*) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword*) (port)) = ((dword) (val)))
19. 使用一些宏跟踪调试
A N S I标准定义了5个预定义宏:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
如果编译器不是标准的,可能只支持上面几个宏或根本不支持。另外,编译器或许支持其他的预定义宏。
__DATE__:它文本替换为“Mmm dd yyy”格式的日期,表示代码预处理时的日期。
__LINE__:当前源代码的行号,它可以随着#line指令而改变。
__FILE__:当前源文件的名称。
__TIME__: 源代码编译的时间。
__STDC__:如果当前编译器是标准的,它的值为1,否则是未定义。
可以定义宏,比如定义_DEBUG_宏输出数据信息和代码所在文件所在行。
#ifdef _DEBUG_
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
20. 宏定义防止使用时错误用小括号包含。
譬如:
#define ADD(x, y) (x + y)
可以使用 do{}while(0) 包含多条语句防止出错,譬如:
#define DO(x, y) (x + y); \
x++;
再者:
if(a > b)
DO(a, b);//出现错误
else
...
这并不符合if语句的用法,因修改为:
#define DO(x, y) do{ \
x + y; \
x++; \
}while(0)
-END-
没有回复内容