> 文档中心 > define定义的宏详解

define定义的宏详解

今天书接上回,接着聊关于预编译和#define的知识。

今天也要心情愉悦哦。

在这里插入图片描述

预定义的一些符号和指令

在这里插入图片描述

FILE //进行编译的源文件
LINE //文件当前的行号
DATE //文件被编译的日期
TIME //文件被编译的时间
STDC //如果编译器遵循ANSI C,其值为1,否则未定义

define定义宏

定义带参数的宏

#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
1.参数列表的左括号必须与name紧邻。
2.如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
看个例子:

#define SQUARE(a) (a*a)int main(){int a = 9;printf("%d", SQUARE(a));return 0;}

这是定义一个宏来进行求一个数的平方,需要注意的点是SQUARE后面的()必须紧挨着不能有空格,而且宏内容尽量带上(),为了防止一些因为符号带来的计算错误
就比如,还是还是上面的宏,如果我要是传(4+5)呢?

#define SQUARE(a) (a*a)int main(){printf("%d", SQUARE(4+5));return 0;}

在这里插入图片描述
这样就好像跟我们想象中不一样,为什么是29呢?
首先宏参数也是仅仅是替换的关系,所以替换后变成了(4+5*4+5),这样看的话就变成了29,所以要尽量带上()。

修改后变成了,就不会出错了。

#define SQUARE(a) ((a)*(a))int main(){printf("%d", SQUARE(4+5));return 0;}

tip:

 用于对数值表达式进行求值的宏定义 都应该用这种方式加上括号, 避免在使用宏时由于参数中的操作符或 邻近操作符之间不可预料的相互作用。

有副作用的宏参数

那么在宏参数上还有要一点注意的,就是宏参数在宏内容上被多次使用时,要考虑副作用。
看个例子:大家可以计算下结果

#define CMP(a,b) (a>b?a:b)int main(){int a = 10;int b = 20;int c = CMP(a++, b++);printf("a = %d\n", a);printf("b = %d\n", b);printf("c = %d\n", c);return 0;}

在这里插入图片描述
这里,就会发现,这里的参数就奇怪,传的是a++和b++,这里的宏参数就有副作用,就会导致结果不太一样,这里是把a++和b++直接进行替换,比较时,a++进行1次,b++执行了两次,赋值给c时是b++一次的结果。

宏替换的规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意:

1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2 . 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索
3. 是先替换宏参数中的值,在替换宏本身

看个例子 :

#define M 10int main(){printf("M is %d", M);return 0;}

其中"M is %d"中的M不会被替换,而后面的M会被替换。

#和##的作用

#的作用

就上述的例子,如果我们就是想替换字符串中的呢?怎么办?
在C语言中有个很有意思的东西,一起看看把

int main(){printf("胡杨树下\n");printf("胡杨""树下""\n");return 0;}

在这里插入图片描述
这样看的话,就是字符串之间是没有换行就可以一行输出,效果一样。那么我们可以使用 #把参数插入字符串中
例:

#define PRINT(FORMAT,NUM) printf\("the numeber of "#NUM " is " FORMAT"\n",NUM)int main(){int a = 0;int b = 0;int c = 0;scanf("%d %d %d", &a,&b,&c);PRINT("%d", a);PRINT("%d", b);PRINT("%d", c);return 0;}

在这里插入图片描述
这里可以看是通过宏和#的作用是可以达到上述的效果的。
#的作用也就看出了,#的作用是把宏参数变成相对应的字符串。

那么##的作用的?

也比较少见,看个例子 :

#define LINK(huayang,shuxia)  (huyang##shuxia)int main(){int huyangshuxia = 10;printf("%d\n", LINK(huyang, shuxia));return 0;}

在这里插入图片描述
##的作用是,可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符。就像拼图一样,把两个符号,合成一个由宏定义的符号。

下期预告:

因为预处理知识太多了,害怕各位看官没有耐心,
本期就到这里结束,下期继续,下期更精彩~~~
在这里插入图片描述