#define预处理详解--宏和函数的7大区别

前言

我们经常会使用#define定义一个常量,但对#define这个标识符的了解并不多,总会有如#define使用时有没有什么坑、#define怎么定义宏、定义的宏和函数有什么区别等一堆疑问,今天这篇文章就带你走近科学,走进#define。

#define预定义标识符

#define的语法为:

#define name(名称) stuff(内容)

当stuff过长时,为了代码的美观,需要分几行来写,方法为:
除了最后一行,每一行的后面都加上续行符 ’ / ’

#define PRINT printf("%s","hello,\
							welcome   \
							to my        \
							world!")
//在同一行上,续行符前面可以出现空格(被当做是stuff的一部分),但在该行的续行符后面不能出现任何字符

当然了,我们也许还会疑惑#define后面到底要不要加分号 ’ ; ',答案是最好不要,可以看一下以下代码

#define MAX=1000;
if(1)
	int max=MAX;
else
	max=7;

这段代码就直接出问题了,因为这段代码的MAX经过替换后就相当于以下代码

#define MAX=1000;
if(1)
	int max=1000;;//2个分号,造成else前面没有if,代码出错
else
	max=7;

这里再补充5个预定义符号

 _FILE_           //进行编译的源文件
 _LINE_			  //文件当前的行号
 _DATE_			  //文件被被编译的日期
 _TIME_			  //文件被编译的时间
 _STDC_			  //如果编译器遵循ANSI C,其值为1,否则未定义
这些内容都可以以%s或%d的格式进行打印

#define定义宏

#define机制有一个规定,就是允许把参数替换到文本中,这种实现就被称为宏

宏的声明方式

#define name(parament-list) stuff
#define 名称(参数列表) 内容

这里需要注意2点
1. 参数列表的左括号必须与name相连,不能有任何空白存在,否则参数列表就会被当作内容(stuff) 的一部分
2. 宏只会对传过来的参数进行简单的替换,具体步骤为:
· 在调用宏时,看看是否包含任何#define包含的符号,若有,则对他们进行替换
例如:

#define MAX 100
#define ADD(x,y) ((x)*(y))
int main()
{
	int sum=ADD(MAX,10);
	return 0;
}

先对MAX进行替换

#define MAX 100
#define ADD(x,y) ((x)*(y))
int main()
{
	int sum=ADD(100,10);//进行替换
	return 0;
}

· 替换文本随后被插入到程序中原来的位置,对于宏参数名被他们的值替换
· 最后对结果文件进行再次扫描,看看是否还包含任何有#define定义的符号,若有,则重复以上步骤

下面通过一道题来测试你是否真的知道宏的参数的替换

#define FUNCTION(x,y) x*y
int main(
{
	printf("%d",10*FUNCTION(9+1,10));
	return 0;
}
问这道题输出什么?

有的人想说1000,但又不敢说,怕有什么坑,答案确实不是1000,而是100,但为什么是100呢?前面已经说过了宏只是简单的替换,不会对参数进行运算

10*FUNCTION(9+1,10)

经过替换后变成了

10*9+1*10

答案便是100了,所以在定义宏时,参数和整体都要加括号,以避免意想不到的错误

#define FUNCTION(x,y) ((x)*(y))

如果我们想对一个宏的名字进行重定义,可以使用#undef这条指令

#define MAX 100
int main(void)
{
	printf("%d",MAX);
	#undef MAX;//把MAX这个名字移除了
	return 0;
}

2个有意思的符号:“#”和“##”

‘#’

这个符号可以把宏的参数插入到字符串里面
这里先进行一下铺垫,在接着往下面讲
1.
printf函数可以把要打印的两个字符串连接起来

        ____    _____
printf("hello ""world");//这是2个字符串,连接起来后相当于printf("hello world");

2.
当预处理器搜索#define定义的符号时,字符串常量的内容并不被搜索,也不会在字符串常量里面寻找参数符号

#define MAX 100
#define PRINT(n) printf("The n is not MAX ");
int main()
{
	int n=9;
	PRINT(N);
	return 0;
}
我们希望他可以打印“The 9 is not 100”
但由于字符串常量内容并不被搜索,所以打印“The n is not MAX”

铺垫完成,下面通过例子说明 ’ # ’ 有什么用,我们想实现这样一个功能:
当我们把一个大小为10的整型n当作参数时,就会打印:The value of n is 10;
当我们把一个大小为10的整型a当作参数时,就会打印:The value of a is 10;
当我们把一个大小为1.7的浮点型k当作参数时,就会打印:The value of k is 1.7;
于是我们就可以这样做

                                   ______________        ____(2个字符串)
#define PRINT(value,format) printf("The value of" #value "is"format,value);

传参时这样写

int n=7;
PRINT(n,"%d");

上面的#value直接被替换成 “n” (双引号也是替换的内容,这时变成了一个字符串),如果传的是a,则#value被替换成 “a”;因此前面例题传参后就相当于

       ______________ ___ ___(3个字符串)
printf("The value of" "n" "is" "%d",value );

‘##’

把两边的符号合成一个符号
直接看例子就行了

#define COMBINE(x,y) x##y
int main()
{
	int MaxPrice=99;
	printf("%d",COMBINE(Max,Price));//相当于printf("%d",MaxPrice);
	return 0;
}

需要注意的是以上2个符号只能在宏里面才能使用

宏和函数的7大区别

在这里插入图片描述

参数的副作用是指类似于自加加、自减减这种,自身的值也会永久性的改变
带有参数的副作用对宏的影响可以看以下例题

#define CMP(x,y) ((x)>(y)?(x):(y))
int main()
{
	int x=5;
	int y=8;
	int ret=CMP(x++,y++);
	printf("%d %d %d",ret,x,y);
}
问输出什么

以上代码进行替换后就相当于

  (1)   (2)   (3)   (4)
((x++)>(y++)?(x++):(y++))

首先是(1)和(2)进行比较,5>8为假,要执行(4)语句,因为(1)和(2)有后置加加,此时x=6,y=9,接着执行(4)语句,即 ret 的值为9,最后(4)再执行后置加加,y=10

结语

以上就是本文的所以内容,本文重点在宏和函数的7大区别,相信现在你已经对其有所了解,如果本文有什么讲得不对的地方,恳请指正,如果读者对本文有什么好的建议,欢迎在评论区留言,您的回馈将会铸就下一次更好的体验。当然了,如果你觉得本文对你的帮助很大,可以给博主充一下电,只需要动动小手点赞收藏加关注就行了。

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值