C语言中,#
表示其为预处理命令,define
为宏定义命令。
可以用#define
定义一个标识符来表示一个常量。其特点是:定义的标识符不占内存
,只是一个临时的符号,预编译后的这个符号就不存在了。
#define
又称宏定义,标识符为所定义的宏名,简称宏。宏名表示的是一个常量,可以给变量赋值。
宏定义最大的好处是方便程序的修改
,使用宏定义可以用宏代替一个在程序中经常使用的常量。且当常量比较长时,使用宏就可以用较短的标识符来代替,这样编程更方便不易出错。宏定义的优点是方便和易于维护
。
在预编译时,会将程序中所有出现标识符的地方用这个常量替换,称为宏替换
或宏展开
,预编译所执行的操作就是简单的文本替换。预编译指令不是语句,所以后面不能加分号。
用#define
定义标识符一般形式为:
#define 标识符 常量 //注意, 最后没有分号
宏所表示的常量可以是数字、字符、字符串、表达式
,其中最常用的是数字。
#define
作用域为自#define
那一行起到源程序结束。如果要终止其作用域可以使用#undef
命令。
#define PI 3.14159
#define NAME Kitty
int main(void)
{
double r = 1;//圆半径
double s = PI * r * r;//圆面积 //这里将PI替换为3.14159
printf("s = %f\n", s);
printf("my name is %s", NAME);
return 0;
}
#define FUNCA(a, b) a+b
#define FUNCB(a, b) (a+b)
template
T func(T a, T b)
{
return(a + b);
}
int main(void)
{
int a = 1;
int b = 2;
printf("a * FUNCA(a, b) * b = %d", a*FUNCA(a, b)*b);
printf("a * FUNCB(a, b) * b = %d", a*FUNCB(a, b)*b);
printf("a * func(a, b) * b = %d", a*func(a, b)*b);
return 0;
}
//结果 //仅文本替换,可以看出有无括号的区别
a * FUNCA(a, b) * b = 5 //= a*a+b*b
a * FUNCB(a, b) * b = 6 //= a*(a+b)*b
a * func(a, b) * b = 6 //函数调用
#
的用法宏定义中的#
是字符串化操作符。其作用是:将宏定义中的传入参数名转换成一对用双引号括起来的参数名字符串。其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。
#define STR(str) #str
int a = 123;
STR(a); //这里的宏会扩展为"a"
#define PRINT(x) printf("the square of " #x " is %d.\n", (x)*(x))
PRINT(2);//the square of 2 is 4.
PRINT(2+1);//the square of 2+1 is 9.
对空格的处理
当传入单个参数名,忽略传入参数名前面和后面的空格;
如STR( a )
会被扩展为 “a”
当传入的多个参数名之间存在空格时,编译器会自动连接各个子字符串,中间只保留一个空格,忽略其余空格。
如STR( a b )
会被扩展为 “a b”
##
的用法##
是连接符号,把参数连接在一起。
#define CAT(X, Y) X##Y
int XY = 2023;
printf("%d\n", CAT(X, Y)); //这里CAT(X, Y)把X和Y连接在一起,变为XY,XY需要提前声明,否则会找不到XY而产生未定义的错误
#define paster( n ) printf( "token" #n " = %d\n", token##n )
int token9 = 9;
paster(9); //token9 = 9
@#
的用法字符化操作符,只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用是将传的单字符参数名转换成字符,以一对单引用括起来。
#define makechar(x) @#x
a = makechar(b); //a = 'b'
/
的用法当定义的宏不能用一行表达完整时,可以用"/"表示下一行继续此宏的定义。
...
和__VA_ARGS__
VA_ARGS
是一个可变参数的宏
实现思想就是宏定义中参数列表的最后一个参数为省略号…
,这样预定义宏__VA_ARGS__
就可以被用在替换部分,替换省略号所代表的字符串。
#define PR(...) printf(__VA_ARGS__)
PR("hello\n");
int a = 1, b = 2;
PR("a = %d, b = %d", a, b);
几个系统的宏
__FILE__
宏在预编译时会替换成当前的源文件名__LINE__
宏在预编译时会替换成当前行号__FUNCTION__
宏在预编译时会替换成当前的函数名称a = 1, b = 2;
PR(“a = %d, b = %d”, a, b);
几个系统的宏
__FILE__
宏在预编译时会替换成当前的源文件名__LINE__
宏在预编译时会替换成当前行号__FUNCTION__
宏在预编译时会替换成当前的函数名称参考了一些文章: