目录
1.#define定义常量
基本语法使用
#define MAX 100
举个例子
#define MAX 100
int main()
{
int a=MAX;
}
在编译器预处理阶段会自动将main函数中所有的出现的MAX替换成100
2.#define定义宏
基本语法使用
#define sum(x) x+x
举个例子
#define sum(x) x+x
int main()
{
int a=sum(5);
}
这个宏接收一个参数x.如果在上述声明之后,将sum(x)置于函数,预处理器会用下门这个表达式替换上面的表达式:5+5;
int main()
{
int a=5+5;
}
3.宏替换的规则
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int a = MAX(3,2);
return 0;
}
例如写一个宏找两个数的最大值,以此观察宏的替换规则。
1.在调用宏时,首先对参数进行检查,看着是否包含任何由#define定义的符号。如果是,它们首先被替换。
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3.最后,再次对结思文件进行扫描,看看它是否包含任何由#define定义的符号,如果是,就重复上述处理过程。
4.宏参数和#define 定义中可以出现其他#define定义的符号,但是对于宏不能出现递归。
5.当预处理器搜索#define定义的符号的时候,字符单常量的内容并不被搜索。
4.宏函数的对比
int sum(int x,int y)
{
int c=x+y;
return c;
}
#define sum(x,y) x+y
进行一个简单的加法时,普通函数首先要进行传参,然后再将计算好的值传回主函数,相对于宏函数更浪费空间和时间,而且函数进行传参时,还要考虑x,y的类型,如果是float类型,则函数需要进行相应的改变,而宏函数直接将主函数的内容替换不需要考虑x,y的类型。
5.#和##
1.#运算符
#运算符将宏的一个参数转换为字符串字面量,它仅允许出现在带参数的宏替换列表中。
#运算符所执行的操作可以理解为“字符串化”。
int main()
{
int a = 5;
printf("the size of a is %d\n", a);
int b = 6;
printf("the size of b is %d\n", b);
float c = 2.5f;
printf("the size of c is %f\n", c);
return 0;
}
多个重复printf使代码繁琐且浪费空间,因此可以用宏定义函数
而单纯的n是当成字符串里的字符直接打印的,编译器并未将其替换,因此需要#将n进行字符串化。将其优化为以下代码。
2.##运算符
##可以把位于它两边的符号合成一个符号,它允许宏定义从分类的文本片段创建标识符,##被称为记号粘合这样连接必须产生一个合法标识符,否则结果未定义。
例如,写一个函数求2个数的较大值时,不同的数据类型得写不同函数。
int int_max(int x,int y)
{
return x>y?x:y;
}
float float_max(float x,float y)
{
return x>y?x:y;
}
这样写过于繁琐,现在我们这样写代码试试:
#define GENERIC_MAX(type) \
type type##_max(type x,type y) \
{ \
return x>y?x:y; \
}
""是连接符,定义宏是可能代码过长,导致一行无法容纳,以此可以使用连接符将多行代码连接起来。
运行结果:
6.关于宏的注意事项
1.注意分号的使用
定义宏时一般不需要加分号,否则可能使代码出错
#define A 10;
int main()
{
int n=0;
if(n>0)
n=A;//宏直接将A替换 n=10;;
else
n=0;
return 0;
}
以上代码导致if后面含有两条语句,导致else无法与if匹配,使代码错误。
2.宏尽量都带括号
宏替换时并不会将参数进行计算,而是直接带入,由于乘法的优先级高于加法因此得出a=10,但我们预期的确实a=25,所以我们需要加上括号。例如以下代码:
3.含有副作用的宏参数
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
int a=1;
int b=2;
int c=(a++,b++);
}
宏替换后
int c=((a++)>(b++)?(a++):(b++))
如果a>b,a自增两次,b自增1次,反之a自增1次,b自增两次,与我们预期的结果并不相同,因此在选用宏时尽量避免使用++或–。