C语言:#define详解

#define定义标识符

语法:
#define name stuff
tips:我们在define定义标识符的时候,不建议在后面加上 ;,这样很容易出问题。比如说在以下的情况中:

if
(
condition
)
max
=
MAX
;
else
max
=
0
;

 #define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。

宏的申请方式:#define name( parament-list ) stuff

其中的
parament
-
list
是一个由逗号隔开的符号表,它们可能出现在
stuff
中。
如果我们要写
#define SQUARE( x ) x * x 这样的一个宏。
#define SQUARE(x) x*x //参数列表的左括号必须与name紧邻

int main()
{
    int r = 5;
    printf("%dn", r);
    
    return 0;
}

打印出来的结果就是25。但是这样一个宏定义也存在着一定的问题。如果说我们传进去的值是5+1,那么它打印出来的结果会是11而不是36。

原因就在于5+1是替换掉宏定义中的x。就变成了int r = 5+1*5+1。只需要加上括号即可解决,#define SQUARE(x) ((x) * (x))。

 #define替换规则

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

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

#和## 

 #可以把参数插入到字符串中

#define PRINT(N) printf("the value of "#N" is %dn", N)

int main()
{
    int a = 10;
    PRINT(a);

    int b = 20;
    PRINT(b);

    return 0;
}

在N的前面加上#,N的参数不会替换成它本身,而是会转换成对应的字符。

##可以把位于他两边的符号合成一个符号

#define CAT(Class,Num) Class##Num

int main()
{
    int Class100 = 100;
    printf("%dn",CAT(Class,100)

    return 0;
}

 这个例子表达的是,CAT有两个参数,##会把两个参数合成一个符号,所以打印的就是100。

带副作用的宏参数 

 当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能 出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。

x
+
1
;
//
不带副作用
x
++
;
//
带有副作用
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8; 
z = MAX(x++, y++);

printf("x=%d y=%d z=%dn", x, y, z);

最终的结果是:x=6,y=10,z=9 

宏和函数对比 


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

命名约定 

一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:把宏名全部大写,函数名不要全大写

 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>