平时常说的 C 语言三大预处理功能是什么?(吹牛谈资,不能不知)
答:宏定义;文件包含;条件编译。
说到底,宏定义的实质是什么?
答:替换。
关于宏定义有一点大家一定要了解,就算再复杂,它也只是替换,不做计算,也不做表达式求解。
请问下面的宏为什么无法比较 x 和 y 两个参数的大小?
#define MAX (x, y) (((x) > (y)) ? (x) : (y))
答:这是由于在 MAX 和参数 (x, y) 之间存在空格导致的。
从初学者的角度来看,带参数的宏定义和函数十分相似,你作为渐入佳境的大牛,你能否从实现逻辑上指出它俩的不同之处?
答:虽然宏定义也有所谓的”形参“和”实参“,但在宏定义的过程中,并不需要为形参指定类型。这是因为宏定义只是进行机械替换,并不需要为参数分配内存空间。
而函数不同,在函数中形参和实参是两个不同的变量,都有自己的内存空间和作用域,调用时是要把实参的值传递给形参。
下面这个宏定义存在什么安全隐患?
#define SQUARE(x) x * x
答:如果单独传入一个数字,那是没问题的。
但如果你传入一个式子,那么问题就来了。
比如传入 3+2,那么宏定义替换后的结果便是 3+2 * 3+2,显然不能获得预期的计算结果。
比较稳妥的做法给参数也加上小括号:#define SQUARE(x) ((x) * (x))
课堂中留下的问题,请问下面宏定义隐藏着一个难以发现的 BUG,请你找出来?
#define SQUARE(x) ((x) * (x)
答:当宏定义的参数遇到 ++、-- 运算符的时候,BUG 出现
下面是触发 BUG 的代码:
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main(void)
{
int i = 1;
while (i <= 5)
{
printf("%d 的平方是%d\n", i-1, SQUARE(i++));
}
return 0;
}
看,程序完全不按套路出牌:
但如果将宏定义改成函数:
#include <stdio.h>
int square(int x);
int square(int x)
{
return x * x;
}
int main(void)
{
int i = 1;
while (i <= 5)
{
printf("%d 的平方是%d\n", i-1, square(i++));
}
return 0;
}
程序妥妥地按照我们的要求去实现:
这是因为 C 语言默认将参数从右到左的顺序依次入栈,参数和局部变量都是存放在栈中的,还记得吧?
printf("%d 的平方是%d\n", i-1, SQUARE(i++));
SQUARE(i++) 先展开了,变成 ((i++) * (i++))。
由于 ++ 在后,所以是先使用 i 的值,再自增,上面式子的结果是 1,完事之后 i 的值变成了 3(自增了两次)。
所以,第一次打印便是:2 的平方是 1
同样的道理,第二次先展开 SQUARE(i++),此时 i 的值是 3,完事之后变成 5,所以第二次打印便是:4 的平方是 9。
大千世界,无奇不有,学习编程,就要动手!
不要想当然,哈哈哈哈~