记住宏函数并非真函数,就是一个字符串的替代动作,预编译阶段处理成真代码
1:基础宏函数
#include#include #include //宏的定义 // 形式: // #define 宏名称 替换主体 //宏函数的特点: // 1: 效率高,非真函数,只是字符串替换, 所以结尾";"可有可无 // 2: 可重复调用。 // 3: 核心是字符串替换操作,只是预编译阶段进行的简单的替换,宏也不是类型定义。 // 4:由于是字符串替换,必须要注意结合顺序,给足括号,防止意外。 // 5: 宏 起到指挥编译具体目标的作用,如#ifdef,可见 宏 的主场是预编译阶段。 // 6:辅助实现了可变数量参数功能 //部分预定义宏,在预编译阶段转为实际的代码 // 本机日期 __DATE__ // 文件名 __FILE__ // 行号 __LINE__ // 本机时间 __TIME__ #define sqr(x) (x)*(x) //一定要注意括号给足 #define my_pt(x) printf("%s %srn",x,__DATE__) int main(int argc,char** argv) { printf("ret = %drn",sqr(5+1)); printf("%srn",__DATE__); printf("%srn",__TIME__); printf("%srn",__FILE__); printf("%drn",__LINE__); my_pt("this define means string exchange=> "); return 0; }
2:hentai喜欢写的多参宏函数
#include#include #include //__VA_ARGS__需和define一起使用:将左侧宏名称中的...原样抄到右边的__VA_ARGS__地方 #define PT(...) printf(__VA_ARGS__) //原样全抄,其实并没啥意义,只是换了个调用名字,在宏内不能增加操作了,还算啥“宏函数” #define PT_A(...) printf(__VA_ARGS__"rn") //简单追加,记住宏的内核是简单替换 #define PT_B(...) printf("fun in %s,"__VA_ARGS__"rn",__FILE__) //将传入的替换,并且再做两侧追加系统预定义宏 #define LT(fm,...) printf(fm,__VA_ARGS__) // #define LT(fm , ...) printf(fm,__VA_ARGS__,__FILE__)//无法做追加操作,无法编译,其实是替换后的编码格式不对了 // #define LT(fm , ...) printf(fm,__FILE__,__VA_ARGS__)//无法做追加操作 // #define RT(fm,...) printf(fm,##__VA_ARGS__) //单独的##__VA_ARGS__没啥意义 //因为是核心是预编译的字符串替换操作,所以“,”会导致决定是否能编译,即决定编码内容格式。 #define RT_A(fm,...) printf(fm"fun in %s,line %d:rn",##__VA_ARGS__,__FILE__,__LINE__) #define RT_B(fm,...) printf("fun in %s,line %d:rn"fm,__FILE__,__LINE__,##__VA_ARGS__) //调整替换追加顺序也可以 //关键处:fm"fun in %s,line %d:rn",##__VA_ARGS__ //关键处的关键##__VA_ARGS__ //1:如果可变参数被忽略或为空,## 操作将使预处理器(preprocessor)去除掉它前面的那个逗号 //ep: RT_A("this is const"); =>printf("this is const""fun in %s,line %d:rn",__FILE__,__LINE__) //2:如果你在宏调用时,确实提供了一些可变参数,GNU CPP 也会工作正常,它会把这些可变参数放到逗号的后面,匹配前面的fm规定格式 //ep: RT_A("a=%d,b=%d,sum=%drn",a,b,a+b); => printf("a=%d,b=%d,sum=%drn""fun in %s,line %d:rn",,a,b,a+b,__FILE__,__LINE__) //ep:前侧可再多定义一个"参数",format位置也可以调换,但都是和" %s-%d:"连体的。 //#define LOG(Priority,format,...) syslog(LOG_DEBUG," %s-%d:" format,__FILE__,__LINE__,##__VA_ARGS__) //猜测这个顺序也行#define LOG(Priority,format,...) syslog(LOG_DEBUG,format" %s-%d:",##__VA_ARGS__,__FILE__,__LINE__) int main(int argc, char ** argv){ int a = 10; int b = 20; PT("this is a simple copy from ... to __VA_ARGS__"); //只能直接copy PT_A("this is a simple copy from ... to __VA_ARGS__"); //注意这里存在一个前提,宏函数必定会对传入数据进行操作,不存在直接完全拷贝的情况,这是无意义的 PT("this is a simple copy from ... to __VA_ARGS__ %d %d",a,b); //能过编译,但这种完全直接拷贝做法毫无意义 // PT_A("this is a simple copy from ... to __VA_ARGS__ %d %d",a,b); //编译不通过,在宏函数中对传入变量进行了操作,就报字符串连接错误了 // PT_B("this is a simple copy from ... to __VA_ARGS__%d %d",a,b); //编译不通过,在宏函数中需要操作变量时,出现同上问题 printf("rn"); LT("a=%d,b=%d,sum=%drn",a,b,a+b); //替换了两段东西,前半段fm,后半段...,所以后半段的,分隔是可变的,反正都去替换为__VA_ARGS__了,所以后半段参数量可变。 //但是不能在宏函数中追加别的动作了 printf("rn"); RT_A("this is const"); RT_A("a=%d,b=%d,sum=%drn",a,b,a+b); RT_B("a=%d,b=%d,sum=%drn",a,b,a+b); }
结合下面两个地址看:
https://www.codersrc.com/archives/9450.html
https://www.codersrc.com/archives/9480.html
常见还有常见宏使用的#,##用法:
#:
把后面的参数换成参数字符串
//和define定义的宏函数一起使用,获得 传入宏函数的参数的变量名。
#define new_print(A) printf(%s %d rn“,#A,A);
int main(){
int age = 10;
new_print(age);
}
=》 age 10
##:(宏函数内的粘接剂)
#define new_fun(parm) print##parm("this is a printfrn");
int main()
{
//new_fun(oh); //无法编译通过
new_fun(f);
return 0;
}
=》this is a printf
即等于最终执行了printf("this is a printfrn");
linux内核中的#define有大量出现##这个粘接剂ep:
#define MAX8925_LDO(_id, min, max, step)
{
.desc = {
.name = "LDO" #_id,
.ops = &max8925_regulator_ldo_ops,
.type = REGULATOR_VOLTAGE,
.id = MAX8925_ID_LDO##_id,
.owner = THIS_MODULE,
},
.step_uV = step * 1000,
.vol_reg = MAX8925_LDOVOUT##_id,
.vol_shift = 0,
.vol_nbits = 6,
.enable_reg = MAX8925_LDOCTL##_id,
.enable_bit = 0,
}



