请看正文
C语言有许多预处理命令,#define是其预处理命令之一。所有预处理命令以“#”号开头,如包含命令#include,标准错误指令#error,#pragma指令等。#define指令用于宏定义,可以提高源代码的可读性,为编程提供方便,一般放在源文件的前面部分。
本文简要总结#define指令的多种用法及其注意事项。
1、无参数定义
定义形式如下:
#define 标识符 字符串
无参数宏定义不含参数,常用于常量定义或重新定义数据类型。
1) 常量定义
在编程应用中,对于频繁使用或具有特殊意义的数字可以采用宏定义,在编译预处理时,对程序中所有出现的宏名,都用定义的字符串代替。如:#define PI 3.1416,这样在对源程序作编译时,将先由预处理程序进行宏代换,即用3.1416去置换所有的宏名PI,然后再进行编译。切记不要定义成#define PI=3.1416,这是新手常犯错误。
如果不再使用已定义过的宏,可以用#undef命令终止该宏定义的作用域。
2) 重新定义数据类型
可以把已有类型定义成一个你想要的新类型名,如#define FT float。编写源程序时可用FT替代float;在编译预处理时则将FT全都替换成float。
2、带参数定义
C语言允许宏带有参数,使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。同时也不需要像函数调用那样保留现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都带来一定的时间开销。与函数类似,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参数宏定义的一般形式为:
#define 宏名(形参表) 字符串
如定义一个求两个量的乘积的带参数宏,可以按如下形式定义:
#define MULTIPLY(a,b) ((a)*(b))
假如源程序中有MULTIPLY(5,6),则在编译预处理时,会用((5)*(6))来替代。
注意,在定义宏时一定要把字符串用括号括起来,并且每一个参数均需括起来,否则程序有可能不会按照你的意图执行。如果你把宏简单地定义成了如下形式:
#define MULTIPLY(a,b) a*b
此种定义下,若源程序中有MULTIPLY(2+3,3+3),编译预处理时不会做任何计算,即绝不会先计算2+3和3+3再替换,而是直接替换。那么结果将会是2+3*3+3=14,已经不再符合编程的预期结果30。
3、多行定义
#define可以进行多行定义,用于替代多行语句代码。定义形式如下:
#define MACRO(参数列表)do{ \
语句1; \
… \
语句n; \
}while(0)
切记,需要在每行的末尾一定要加上“\”,起到换行的作用。
4、单行定义
#define Conn(x,y) x##y /* x##y表示什么?表示x连接y */
#define ToChar(x) #@x /* #@x,其实就是给x加上单引号 */
#define ToString(x) #x /* #x是给x加双引号 */
5、用#define来处理头文件嵌套包含问题
由于头文件包含可以嵌套,那么c文件有可能包含多次同一个头文件,就可能出现重复定义的问题的,那么可以就通过条件编译开关来避免重复包含,一般头文件可以做如下定义:
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件内容
…
#endif
6、#define特性及使用说明
1) 宏名一般用大写,且宏定义末尾不加分号;
2) 宏定义通常在文件的最开头,作用域通常从定义处到文件末尾,也可以用#undef命令提前终止宏定义的作用域;
3) 宏定义不存在类型问题,它的参数也是无类型的,编译预处理不做语法检查,不分配内存;
4) 字符串" "中永远不包含宏;
5) 编程时使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。
领取专属 10元无门槛券
私享最新 技术干货