小小知识之预处理 *** 作

小小知识之预处理 *** 作,第1张

前言

和大家一起学习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的值就会发生改变。

所以在宏的副作用中也是会出现这样的情况,会带来不可预测的后果,所以我们要谨慎使用宏。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/674714.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存