1 不带参宏定义
这种用法是最简单最常见的一种方式,如下:
#define PAI 3.14
注意:
- 宏定义原则上用大写表示,虽然这并不是规定
- 由于宏定义是预处理指令,并非是C语言语句,所以末尾不必加分号
它的功能是在程序中若出现了PAI
,就把它替换为3.14
,示例程序如下:
#include <stdio.h>
#define PAI 3.14 // 不带参宏定义
int main() {
double r = 2;
printf("半径为%.2lf的圆的周长为%.2lf", r, 2*PAI*r);
return 0;
}
2 带参宏定义
使用方法如下:
#define ADD(a,b) (a+b)
它的功能是计算a+b
的结果,示例程序如下:
#include <stdio.h>
#define ADD(a,b) (a+b)
int main() {
int a = 1;
int b = 2;
printf("a+b=%d", ADD(a, b));
return 0;
}
这里需要注意的是,我们习惯上会把后面表达式添上括号,如(a+b)
,在本例中去掉这个括号也是可以的,但有些情况下会出现问题,如下:
#include <stdio.h>
#define ADD(a,b) a+b
#define SUB(a,b) a-b
int main() {
int a = 1;
int b = 2;
printf("%d", ADD(a,b)*SUB(a,b)); // ab的和与差相乘
return 0;
}
这个程序的功能是计算a+b
乘以a-b
的值,实际上程序的输出结果为1
,我们稍加思考发现本例中a+b>0
,a-b<0
答案必然是负数,结果却是正数,显然出了问题,那么再把表达式的括号加上试试看:
#define ADD(a,b) (a+b)
#define SUB(a,b) (a-b)
程序运行后输出结果为-3
,可以口算发现此结果是正确的,出现问题的原因就要从#define
预编译指令的原理说起,在编译一个C语言程序时,第一步执行的是预编译这个过程中会把#define
中定义的宏进行替换,如不加括号的程序中就替换成了如下:
printf("%d", a+b*a-b); // 输出结果为1
显然根据数学运算规则会先算乘法后算加法,所以结果为1
,那么加上括号的程序中替换后结果如下:
printf("%d", (1+2)*(1-2)); // 输出结果为-3
先算括号里的式子,整个式子的结果显然为-3
,通过本例可以发现为了避免替换后出现类似这种错误,尽量将表达式加上括号,特别是表达式中有多个变量时
带参宏定义和函数有点像,他们的区别如下:
- 函数参数传递时会计算实参的值再传递给形参,如执行函数
func(1+2)
,会先计算1+2
的值为3
再交给函数体,而带参宏定义不进行任何计算,直接替换- 根据上面例子可以发现,带参宏定义对数据类型没有定义,可以使用多种合法类型带入,但函数要根据定义函数时声明的参数类型传递值
- 带参宏定义仅占用预编译的时间,而函数的执行会占用空间和时间,如分配内存空间,入栈保留现场,返回值等
3 与字符串有关的用法
3.1 字符串转换
使用方法如下,在s
前加上#
,它的作用是将传入的s
转换为字符串
#define STR(s) #s
示例程序如下,给出参数Wuhan jia you
,最后以字符串的形式输出来
#include <stdio.h>
#define STR(s) #s
int main() {
puts(STR(Wuhan jia you));
return 0;
}
需要注意的是,转换的是s
,而不是s
里的值,见下面两个程序:
// 程序1
#include <stdio.h>
#define STR(s) #s
int main() {
const char *s = "Wuhan jia you";
puts(STR(s));
return 0;
}
// 程序2
#include <stdio.h>
#define STR(s) #s
int main() {
int n = 2020;
puts(STR(n));
return 0;
}
第一个程序输出结果为s
,第二个程序的输出结果为n
,可见这个用法就是你给它什么,它就把它直接转换为字符串,不管它是不是变量
3.2 字符转换
使用方法如下,在c
的前面加上#@
,它的作用是把c
转换为字符
#define STR(c) #@c
注意:本用法不支持gcc编译器,如在gcc编译器下编译,会出现下面的错误信息
error: '#' is not followed by a macro parameter
,这个用法仅支持微软系列(Microsoft Specific)
示例程序如下,给出参数1
,最后把1
转换为字符1
输出:
#include <stdio.h>
#define STR(c) #@c
int main() {
putchar(STR(1));
return 0;
}
关于它的转换规则和3.1 字符串转换
的类似
3.3 字符连接
使用方法如下,在两个参数中间添加##
,它的作用是连接前后两个参数,把它们变成一个参数
#define CAT(a,b) a##b
示例程序如下
#include <stdio.h>
#define CAT(a,b) a##b
int main() {
int n = CAT(123, 456);
printf("%d", n);
return 0;
}
输出结果为123456