宏的全面解析

本文详细介绍了C语言中的#define预处理器,包括定义标识符、宏定义、#和##的作用,以及带副作用的宏参数问题。强调了宏定义的直接替换机制可能导致的意外行为,并对比了宏与函数在代码长度、执行速度、操作符优先级、副作用和参数类型等方面的差异。同时提到了#undef指令用于取消宏定义。
摘要由CSDN通过智能技术生成

1 .#define 定义标识符

定义的内容可以是一个整型,一个字符,一串字符串,一段代码。

#define MAX 1000
#define  WH  abcd
#define do_forever for(;;)     // 用更形象的符号来替换一种实现
#define CASE break;case         // 在写 case 语句的时候自动把 break 写上。

重点以最后的 #define CASE break;case举例

#include<stdio.h>
#define CASE break;case

//int main()
//{
//	int x = 0;
//	switch (x)
//	{
//	case 1:
//			break;
//	case 2:
//		break;
//	case 3:
//
//	}
//	return 0;
//}


int main()
{
	int x = 0;
	switch (x)
	{
	case 1:
	CASE 2:
	CASE 3:
	}
	return 0;
}

 提问: define定义标识符的时候,要不要在最后加上 ; ?

比如:
#define MAX 1000;
#define MAX 1000

其实并没有强行规定,你只要知道 #define的机制是一个直接替换的机制,如果加了 则替换的时候也要加上 ;

2. #define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏( macro )或定义 宏(define macro )。
下面是宏的申明方式:
#define name( parament - list ) stuff
其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中。
注意:
参数列表的左括号必须与 name 紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

 例子:

#define MAX(x,y) ((x)>(y)?(x):(y))

宏的书写要规范:

合理范围内不要吝啬括号。

例1:

有#define SQUARE( x ) x * x
则SQUARE(4+1)等于多少?
是25吗?

答案是9。

 #define的机制是一个直接替换的机制。

 SQUARE(4+1)等于 4+1*4+1 等于9

例2:

#define DOUBLE(x) (x) + (x)
int a = 5 ;
printf ( "%d\n" , 10 * DOUBLE ( a )); 等于多少?
是100吗?

 答案是55。

同理 10 * DOUBLE(5等于 10*5+5 等于55。

3. ###

3.1#

如何把参数插入到字符串中?

首先我们看看这样的代码:
char* p = "hello ""bit\n" ;
printf ( "hello"" bit\n" );
printf ( "%s" , p );
这里输出的是不是
hello bit
答案是确定的:是。
我们发现字符串是有自动连接的特点的。
当我们想要打印  the value of 变量名 is 具体值类似形式的表达式时。
我们无法有一个通用表达式高效表示,故无法写成函数。
那我们是不是可以写这样的代码?
使用 # 把一个宏参数变成对应的字符串
#include<stdio.h>
#define PRINT(n,format) printf("the value of "#n" is "format"\n",n);

int main()
{
	int a = 10;
	double b = 3.14;
	PRINT(a,"%d");
	PRINT(b, "%.2lf");
	return 0;
}

 3.2##

## 的作用
##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。
#include<stdio.h>
#define CAT(x,y) x##y

int main()
{
	int whabc = 99;
	printf("%d", CAT(wh, abc));
	return 0;
}
注:
(1)这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
(2)##只能在宏里这样用

4.带副作用的宏参数

带副作用?

如:

x + 1 ; // 不带副作用
x ++ ; // 带有副作用
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能 出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
MAX 宏可以证明具有副作用的参数所引起的问题。
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5 ;
y = 8 ;
z = MAX ( x ++ , y ++ );
printf ( "x=%d y=%d z=%d\n" , x , y , z ); // 输出的结果是什么?

这里我们得知道预处理器处理之后的结果是什么:

z = ( (x++) > (y++) ? (x++) : (y++));

所以输出的结果是:

x=6 y=10 z=9

5. 宏和函数对比

#define 定义宏
函数
代 码 长 度
每次使用时,宏代码都会被插入到程序中。除了非常 小的宏之外,程序的长度会大幅度增长。
函数代码只出现于一个地方;每 次使用这个函数时,都调用那个 地方的同一份代码
执 行 速 度
更快
存在函数的调用和返回的额外开 销,所以相对慢一些
操 作符 优
先 级
宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括 号。
函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数。表达式的求值结果更容易预 测
带 有
副 作
用 的
参 数
参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果
函数参数只在传参的时候求值一 次,结果更容易控制。
参 数
类 型
宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。
函数的参数是与类型有关的,如 果参数的类型不同,就需要不同 的函数,即使他们执行的任务是
相同的。
宏是不方便调试的
函数是可以逐语句调试的
宏是不能递归的
函数是可以递归的
命名约定
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写

 

6. #undef

这条指令用于移除一个宏定义。

#undef NAME
// 如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

以上为我个人的小分享,如有问题,欢迎讨论!!!  

 

 

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值