一句话,宏定义就是全局替换和声明的一种方式!
我原本以为没必要详细了解,后来发现做错了题,纠结之后还是整理一下好了。
宏定义掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换!
不含参#definePI3.1415926
把程序中出现的PI全部换成3.1415926!
#defineendl'\n'
把程序中出现的endl全部换成字符'\n'!
含参例子1#include<iostream>
#defineendl'\n'
#defineSR(x,y)x y
usingnamespacestd;
voidsum1(){
inta=5,b=4;
a =2*SR1(a,b);
cout<<"sum1="<<a<<endl;//结果是19
}
第一步,先换:语句替换后成为a =2*a b。
第二步,替换变量,语句替换后成为5 =2*5 4。
第三步,计算式子,先是右侧公式计算结果为14,此时为5 =14;最后赋值到变量上,结果是19!
例子2#include<iostream>
#defineendl'\n'
#defineSR(x,y)((x) (y))
usingnamespacestd;
voidsum2(){
inta=5,b=4;
a =2*SR2(a,b);
cout<<"sum2="<<a<<endl;//结果是23
}
第一步,先换:语句替换后成为a =2*((a) (b))。
第二步,替换变量,语句替换后成为5 =2*(5 4)。
第三步,计算式子,先是右侧公式计算结果为18,此时为5 =18;最后赋值到变量上,结果是23!
例子3#definefun1(a)a
voidf1(){
cout<<"f1="<<fun1(12 3)<<endl;//结果是数字15
}
#definefun2(a)"a"
voidf2(){
cout<<"f2="<<fun2(12 3)<<endl;//结果是字符串a
}
请看清楚,定义的后面究竟是参数本身还是带着双引号的字符串!
含参循环#include<iostream>
usingnamespacestd;
//#definedoit(m,n)for(inti=0;i<(n); i){m =i;}
#definedoit(m,n)for(inti=0;i<(n); i)\
{\
m =i;\
}
intmain(){
inta=5,b=4;
doit(a,b);
cout<<a;//结果为11
return0;
}
宏定义也是可以分行的!!!
宏定义也是可以运行循环的!!!
宏定义也是能让人栽跟头的!!!
宏定义语法特点含#和##- 使用#把宏参数变为一个字符串
- 用##把两个宏参数贴合在一起
#include<iostream>
usingnamespacestd;
#defineendl'\n'
#defineSTR(s)#s
#defineCONS(a,b)int(a##e##b)
intmain(){
cout<<STR(vck)<<endl;//输出字符串"vck"
cout<<CONS(2,3);//2e3输出:2000
return0;
}
#undefCONS
#undefSTR
其实照我现在的理解,有这种复杂需求的话还是写成函数更合适一些。
单纯为了炫技的话,当我没说……
更多详细应用还是参考原文博客吧,传送门在文末。
特点- 宏定义末尾不加分号;
- 宏定义写在函数的花括号外边,作用域为其后的程序,可以用#undef命令终止作用域
- 宏定义可以嵌套
- 字符串""中永远不包含宏
- 宏定义不分配内存,想要分配内存去使用变量吧。
- 预处理不做语法检查。因为预处理是在编译之前的处理,而编译工作的任务之一就是语法检查
- 宏定义不做计算,只作替换
- 宏的哑实结合不存在类型,也没有类型转换。
使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。
例如:数组大小常用宏定义。
与函数的区别- 函数调用是在编译后程序运行时进行,并且分配内存。
- 宏替换在编译前进行,不分配内存
- 函数一般只有一个返回值,特殊情况下用pair也是一个对象,对象内两个值
- 宏则可以设法得到多个值
- 宏展开会使源程序变长,函数调用不会
- 函数调用占运行时间(分配内存、保留现场、值传递、返回值)
- 宏展开不占运行时间,只占编译时间
源文件:
gitee:https://gitee.com/JunKuangKuang/KeenCPPTest-all/tree/main/basic/define
github.com:https://github.com/JunKuangKuang/KeenCPPTest-all/blob/main/basic/define
感谢现在的好奇,为了能成为更好的自己。
王珂的个人笔记