1.定义标识符
定义:#define MIX 100
取消定义:#undef MIX
这里的定义好了后,MIX就可直接在函数中使用,编译阶段会自动把函数中的MIX替换成100,但不是所有的MIX都会被替换。
如:printf(“MIX”);这种情况下输出的仍是MIX,不是100。
使用示例:
#define MIX 100
int mian()
{
int a = MIX;
if(a > 0)
printf("Hello word!\n");
return 0;
}
注意了,定义标识符是最好不要在代码后加分号。如果写的是 #define MIX 100;那么MIX会被替换成“100;”。那编译时就容易出错。如下面一段代码:
#define MIX 100;
int main()
{
int max = 0;
if(condition)
max = MAX;//替换成max = 100;;
else
max = 0;
return 0;
}
其他示例:
①给一些名字比较繁琐的关节字创建一个简短的名字
如:#define reg register
但这样写代码会降低代码的可读性。
②用更形象的符号来替换一种实现
如:#define do_forever for(;;)
③ 在写case语句的时候自动把break写上。
如:#define CASE break;case
2.定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
申明方式:#define name(parament-list) stuff
例题:写一个宏可以将一个数字的奇数位和偶数位交换。
#define exchange(num) ((((num) & (0xAAAAAAAA)) >> 1) | (((num) & (0x55555555)) << 1))
int main()
{
int num = 0;
scanf_s("%d", &num);
printf("%d\n", exchange(num));
system("pause");
return 0;
}
注意:参数列表的左括号必须与name紧邻。 如果两者之间有空格存在,参数列表就会被解释为stuff的一部分。
说到这,这里还有一类非常经典的例题
#define ADD(x) (x)+(x)
int main()
{
int num = 4;
printf("%d", 3 * ADD(num));
system("pause");
return 0;
}
按预期这里应该输出24,但最后结果却是16。因为这里乘法运算优先于宏定义里面的加法运算。解放方法是在宏定义表达式两边加一堆括号:#define ADD(x) ((x)+(x))
。
宏和函数的区别
1. 宏在编译阶段只是对源代码进行简单替换,不会进行任何逻辑检测,就是把代码替换过去。
2. 宏进行定义时不会考虑参数的类型,而函数的参数必须申明为某种类型。
3. 参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。
4. 参数宏的运行速度会比函数快,因为不需要参数压栈/出栈操作。
6. 函数只在目标文件中存在一处,比较节省程序空间。
7. 函数的调用会牵扯到参数的传递,压栈/出栈操作,速度相对较慢。
8. 宏相对于函数来说更加通用,函数形参是申明好的,不能接受其他类型形参。
9. 宏是简单展开替换,用多少次就会替换多少次。函数是调用,不管用了多少次,还是只有一份代码。
10. 宏有带副作用的宏参数。
11. 宏可以传类型,这是函数不能做到的。
注:在C++中引进了内联函数inline的概念,它具有宏的优点同时摒弃了宏的缺点。
冷知识:
①# 把一个宏参数变成对应的字符串。
示例:
#define Print(X) printf("the value of" #X "is %d\n",X)
int main()
{
int m = 2018;
Print(m);
system("pause");
return 0;
}
打印结果:the value ofmis 2018
② ## 可以把位于它两边的符号合成一个符号。他就相当于一个粘合剂,把前后,两部分粘合起来。但“##”只能粘合法的C语言标识符
#define G(x) x+2 ## +3
int main()
{
int ret = G(2);
printf("%d\n", ret);
system("pause");
return 0;
}
打印结果:7