c语言define宏的作用域,C语言进阶【宏定义】编译预处理#define

本文详细介绍了C语言中的宏定义,包括不带参数和带参数的宏定义。强调了宏定义的作用域,指出宏名在定义后直至文件结束都是有效的,可通过#undef终止其作用域。此外,通过示例说明了宏替换的特点,如不分配空间、直接字符串替换,以及在带参数宏定义中如何避免错误的表达式计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言学习笔记

之  编译预处理与宏定义

宏是编译预处理的重要定义,宏定义就像基本数据类型定义一样,可以看作是一种类型,与基本类型不同的是,宏与函数有着密切的相似之处,但是宏是编译时发生作用。

一:不带参数的宏定义

1.一般格式:

#define标识符  字符串标识符即为这个字符串的宏名

2.宏调用:程序中用宏名代替字符串。

宏展开:预编译时将字符串代替宏名的过程。

比如:#define  PI 3.14

这里的PI就是宏名,他代表的是字符串3.14,预编译时将源程序中的所有宏名PI出现的位置都用字符串3.14来替换。比如: 程序中出现PI*5,它的结果实际上是3.14*5

(1)宏名用大写,用来区分普通变量

(2)宏定义不能以分号结束,否则分号将作为字符串的一部分参加宏展开。比如:#define PI 3.1415;//结尾加了分号

a=PI*r*r;

在编译预处理时,将宏展开: a=3.1415;*r*r分号将作为字符串参加运算,很明显是错误的

(3)宏定义只是用来替换字符串的。不管字符串是什么数据类型,总之就是一句话,宏名替换字符串,宏名替换的一定是字符串,即使上述中的3.1415写成了3.1W15。替换后的结果依然是a=3.1W15*r*r。

(4)#define命令定义的宏名范围是从定义命令开始直到源程序文件结束,而且#define定义在文件开头与函数之间。 如果要想提前结束宏定义的作用域,可以通过#undef终止宏名的作用域

(5)宏定义中可以出现已经定义的宏名,可以层层置换。

若宏名中 出现一个被双引号括起来的字符串中时,将不会产生宏替换。

比如:#include

/*宏定义在文件头和函数之间*/

#define R 3.0

#define PI 3.1415926

#define L 2*PI*R //出现了前面已经定义的PI和R

#define S PI*R*R //出现了前面已经定义的PI和

main()

{

/*

当L和S在“”之内时将不会与宏定义产生联系,即不会发生替换

当L和S不在“”之内时,L将被替换成 2*PI*R,S将被替换成 PI*R*R

*/

printf("L=%7.2f\nS=%7.2f\n",L,S);

}

cf011544c838a9b3736b5b3b57b94bd0.png

最后需要注意的是: 宏定义是专用于预处理的一个名词,它的作用就是替换,不分配空间

二:带参数的宏定义

一般格式:

#define宏名(参数表)   字符串

带参数的宏定义并不仅仅是宏名代换字符串,还要进行参数的替换,类似于函数的调用

比如:#define S(a,b) a*b

area=S(3,2);

S为宏名,a和b为形参,程序中调用S(3,2),把实参3和2分别替换形参a和b,所以宏展开是area=3*2;

比如:#include

/*宏定义在文件头和函数之间*/

#define S(a,b) a*b //需要注意的是S和()之间不能有空格

main()

{

int area;

area=S(2,3);//传递给宏S(a,b),然后替换为a*b

printf("area=%d\n",area);

}

b608e4b6cf514c4894c1127321830967.png

(1)上述程序中的参数传递应该很好理解,但是如果把程序改动一下,让实参的值变成S(2+3,3+4),大家肯定会认为是35,但是真的是35吗?我们看一下:#include

/*宏定义在文件头和函数之间*/

#define S(a,b) a*b //需要注意的是S和()之间不能有空格

main()

{

int area;

area=S(2+3,3+4);

printf("area=%d\n",area);

}

54afbf083ccfde6d630b5397ea7070b5.png

竟然是15,并不是我们想象中的35,怎么回事呢?实际上S(2+3,3+4)传递过去后,它的红替换是area=2+3*3+4,这下大家明白了吧。还是一句话,宏定义只是用来替换的,完完全全的原样的替换。那要怎么解决这个问题呢?很简单,在宏定义的时候加上一个括号就可以了,看程序:#include

/*宏定义在文件头和函数之间*/

#define S(a,b) (a)*(b) //需要注意的是S和()之间不能有空格

main()

{

int area;

area=S(2+3,3+4);//传递给宏S(a,b),然后替换为a*b

printf("area=%d\n",area);

}

8f067e18622139d0854752b6a67a8ddf.png

(2)宏定义的宏调用与函数调用的区别

在学习了带参数的宏定义后,是不是觉得这个调用与函数的调用很相似,但是它们完全是不通的两个概念:

函数调用时,先求出实参表达式的值,再将该值传递个形参,而带参数的宏调用只是进行替换,简单的字符替换

函数调用是在程序运行时处理,分配给形参临时内存单元,而宏展开则在编译时进行的,展开的时并不给形参分配内存单元,不进行值传递,也没有返回值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值