预处理——老大宏定义和使用技巧

所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所做的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成的。对当一个源文件进行编译时,系统将自动引用预处理程序中的预处理部分进行处理,处理完毕自动进入对源程序的编译。

C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等,合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块程序设计。

宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的,在C语言中,宏分为有参数和无参数两种。

1、无参宏定义

无参宏的宏名后不带参数,其定义的一般形式为

#define 标识符 字符串

#表示这是一条预处理命令,凡是以#开头的均为预处理命令;define为宏定义命令;标识符为所定义宏名;字符串可以是常数、表达式、格式串等。

常对程序中反复使用的表达式进行宏定义。

说明:1)宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名。

2)宏定义不是说明语句,在行末不必加分号,如加上分号则连分号也一起置换。

3)宏定义必须写在函数外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用”#undef“命令

2、带参宏定义

在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。一般形式为:

#define 宏名(形参表) 字符串

在字符串中含有各个形参。带参宏调用的一般形式为

宏名(实参表);

带参宏定义与自定义函数的区别

1)带参宏定义中,形式参数不分配内存单元 ,因此不必做类型定义;而宏调用中的实参有具体的值,要用它们去代换形参,因此必须作类型说明。这与函数中的情况是不同的,在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行”值传递“。而在带参宏中,只是符号代换,不存在值传递的问题。

2)在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

注意:在宏定义中,字符串内的形参通常要用括号括起来以避免出错。


写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性、可读性、方便性等。

1、防止一个头文件被重复包含

#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif

2、得到指定地址上的一个字节或字

#define MEM_B (x) (*( (byte *) (x) ) )
#define MEM_W (x) (*( (word *) (x) ) )

3、求最大值和最小值

#define MAX (x,y)  ( ( (x) > (y) ) ? (x) : (y) )
#define MIN (x,y)  ( ( (x) > (y) ) ? (x) : (y) )

4、得到一个field在结构体(struct)中的偏移量

#define FPOS (type,field) \
/*lint -e545 */  ( (dword) & ( ( type *) 0)->field)  /*lint +e545*/

5、得到一个结构体中field所占用的字节数

#define FSIZ( type,field ) sizeof ( ( ( type *) 0)->field )
6、按照LSB格式把两个字节转化为一个Word

#define FLIPW( ray ) ( ( ( ( word)  (ray)[0] ) *256 ) + (ray)[1] )
7、按照LSB格式把一个Word转化为两个字节

#define flopw (ray,val ) \(ray)[0] = ( (val) /256 );\
(ray)[1] = ( (val) & 0xff)

8、得到一个变量的地址 (word宽度)

#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void * ) & (var) )

9、得到一个字的高位和低位字节

#define WORD_LO(***) ( (byte) ( (word) (***) & 255 ) )
#define WORD_HI(***) ( (byte) ( (word) (***) >> 8 ) )

10、防止溢出的一个方法

#define INC_SAT(val) (val = ( (val)+1 > (val) ) ? (val) + 1:(val) )


11、对于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) ) )

12、使用一些宏跟踪调试

ANSI标准说明了五个预定义的宏名,他们分别是_LINE_、_FILE_、_DATE_、_TIME_、_STDC_。如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持,记住编译程序也许还提供其他预定义的宏名。

_LINE_及_FILE_宏指令打印所在行数和函数名。_DATE_宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。源代码翻译到目标代码的时间作为串包含在_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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值