时间:2022-09-30 09:27:16 | 栏目:C代码 | 点击:次
预定义符号是系统本身定义的:

语法:#define name stuff (用stuff替换name)
#define MAX 100
#define STR "hehe"
int main()
{
int max = MAX;
printf("%d\n", max); //输出100
printf("%s\n",STR); //输出 hehe
return 0;
}
#define SQUARE(X) X*X
int main()
{
int ret = SQUARE(5);
printf("%d\n",ret); //输出25
return 0;
}
上面的宏定义代码存在一定的问题: 如果我们换一个参数(将5换成5+1)输出的不是36而是11为什呢?
#define SQUARE(X) X*X
int main()
{
int ret = SQUARE(5+1);//替换之后就是(5+1*5+1 = 11)
printf("%d\n",ret);//输出11
return 0;
}
没加括号
因此,用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或临近操作符之间不可预料的相互作用。
正确的代码:
#define SQUARE(X) (X)*(X))
int main()
{
int ret = SQUARE(5+1);
printf("%d\n",ret);//输出36
return 0;
}
#的作用:把参数插入到字符串中
如果我们想要实现一个代码:把参数插入到字符串中 用到“#”

这里参数a,b就插入到了字符串中了
##的作用:可以把位于它两边的符号合成一个符号,它允许宏定义冲从分离的文本片段创建标识符。

图中的三句代码是等价的:
printf(“%d\n”,AGE(lisa,24));
printf(“%d\n”,AGE(lisa##24));
printf(“%d\n”,AGE(lisa24));
函数和宏都能实现求两个数的最大值
//函数
int Max(int x, int y)
{
return (x > y ? x : y);
}
//宏
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
int main()
{
int a = 10;
int b = 20;
int max = Max(a, b); //输出20
printf("%d\n",max);
max = MAX(a, b);
printf("%d\n", max); //输出20
return 0;
}
通过分析上面的代码实现用宏比用函数会更好,有两个原因:
当然宏相比函数也有劣势的地方:
#define定义宏和函数的对比表格
| 属性 | #define定义宏 | 函数 |
|---|---|---|
| 代码长度 | 每次使用时宏代码都会被插入到程序中除了非常小的宏之外,程序的长度会大幅度增长 | 函数的代码只出现在一个地方,每次使用这个函数时,都调用那个地方的同一份代码 |
| 执行速度 | 更快 | 存在函数的调用和函数的额外开销,所以速度相对慢一些 |
| 操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否者邻近操作符的优先级可能产生不可预料的结果,所以建议宏在书写的时候多用括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。 |
| 带有副作用的参数 | 参数可能被替换带宏中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数参数只在传参的时候求值一次,结果更容易控制 |
| 参数类型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以适用于任何参数类型 | 函数的参数与类型有关,如果参数的类型不同,就需要不同的函数,即使他们执行任务是不同的 |
| 调试和递归 | 宏不方便调试,不能递归 | 函数可以逐语句调试,可以递归 |
命名约定:把宏名全部大写,函数名不要全部大写。
#undef 指令用于移除一个宏定义
当#undef 移除宏定义,再次使用报错。如图 :
