和大家一起学习C语言,如果内容有错误,愿意倾听指点,共同学习,共同进步 0,0
一、#define 相信不少人在学习C语言的时候,常常会用到#define,
我们通常可以把他用来定义一个常量例如:我们要计算圆的面积,
我们可以定义一个PI来表示圆周率的大小,如:#define PI 3.14
这样我们就定义了一个PI表示圆周率的大小,大小为3.14。
但是,其实#define有两个功能,这是其一,另一个是可以定义宏。
定义标识符
通常,定义标识符可以用来
- 可以是赋值
- 可以是为关键字创建一个简短的名字
- 可以是循环 例如:#define do_forever for(;😉
- 甚至可以是语句,例如:
#define DEBUG_PRINT printf(“file:%s\t time:%d\t date%s\t\n”,FILE,TIME,__DATE);
但是,需要记住,#define 是通过替换来实现,所以在#define的最后面可不能加上";",不然在预处理阶段实现替换后,一个语句中就有可能会在末尾包含两个分号,编译器就会报错。
#define NUM 100
#define STR "abcdef"
int main()
{
int num = NUM;//预处理阶段替换成 int num = 100;
char* str = STR;//------------- char* str = "abcdef";
return 0;
}
定义宏
在 #define 机制中包括了一个规定,允许把参数替换到文本中,这种实现通常成为宏,或定义宏。
它的表达形式为:#defien name(parament-list) stuff
注意:
参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
//#define SQUARE(x) x*x //不包含整体括号时
#define SQUARE(x) (x)*(x)//包含整体括号
//#define DOUBLE(x) (x)+(x) //不包含整体括号
#define DOUBLE(x) ((x)+(x)) //包含整体括号
int main()
{
//int a = 10;
//int a = 9;
//int r = SQUARE(a);//当a的初值为10时的结果为: 100
//int r = SQUARE(a + 1);
//当a初值为9时的结果为:19 即在预处理阶段处理为:int r = a + 1 * a + 1 -----9+1*9+1=19
//printf("%d\n", r);
int b = 20;
int ret = 3 * DOUBLE(b);//120
//在预处理阶段替换为:int ret = 3*(b)+(b);--- 3*20+20 = 80 没有整体括号
printf("%d\n", ret);
}
这是因为在替换后引发运算符优先级问题导致的,所以,在用#define 定义宏的时候我们最好把每个元素用括号括起来,最后加上大括号。
例如,我们有这样一个函数
void print(int n)
{
printf("the value of n is %d\n", n);
}
如果我们要用宏来实现这样的函数,该怎么做呢
#define PRINT(N) printf("the value of n is %d\n",N)
但是,如果我们要想输入这样一个程序
int main()
{
int a = 10;//此时结果为 the value of a is 10
//printf("the value of n is %d\n",a);
PRINT(a);
int b = 20;// the value of b is 20
//printf("the value of n is %d\n",b);
PRINT(b);
}
这个程序运行起来,我们只能在结果中看到n的值为什么,n的值为什么,但如果我们想要用他对应的变量名呢,例如:the value of a is 10 像这样的结果我们该怎么做?在函数中,我们没法实现像这样的结果,但是在宏中却可以实现。
例如:
#define PRINT(N) printf("the value of "#N" is %d\n",N);
此时的结果就变成了:
int main()
{
int a = 10;//此时结果为 the value of a is 10
//printf("the value of ""a"" is %d\n",a);
PRINT(a);
int b = 20;// the value of b is 20
//printf("the value of ""b"" is %d\n",b);
PRINT(b);
}
因为在C语言中,使用#,他的实质是把宏参数变成对应的字符串。
这样,我们就可以把字符串放到字符串里。
2. ##
##的作用:它可以把位于它两边的符号合成一个符号
例如: #define CAT(name,num) name##num
在这个预处理指令中,就可以把name和num合在一起成为:namenum 这一个符号
三.带副作用的宏参数
我们来看这一个代码
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
int a = 5;
int b = 8;
int c = MAX(a++, b++);
//int c = ((a++)>(b++)?(a++):(b++))
// 5->6 8->9 (5>8?) 9->10
// 带副作用的宏参数在替换中多次影响
printf("%d\n", c);//9
printf("%d\n", a);//6
printf("%d\n", b);//10
}
当宏参数在宏定义中出现超过一次时,如果参数带有副作用,那么使用宏的时候就会带来危险。
举个例子:
int a =10;
printf("%d\n",a+1);
printf("%d\n",a++);
在这里面,第一个printf使用a的值不改变,但第二个printf使用后,a的值就会发生改变。
所以在宏的副作用中也是会出现这样的情况,会带来不可预测的后果,所以我们要谨慎使用宏。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)