C语言的宏可以分为宏定义和宏函数,宏定义又可以叫做对象式宏,在编译时直接把定义的内容替换到源码处,只是一个文本替换功能,不会进行计算。宏函数又叫做类函数宏,跟函数的使用类似,但是他的本质也是文本的替换,这就有产生很多注意事项。
#define N 10 //宏定义
#define max(a,b) (a>b? a:b) //宏函数
不管是宏定义还是宏函数,本质都是文本替换,把宏名称后面的文本参数替换到源码处,因此我们可以分为没有参数的宏和有参数的宏。
没有参数的宏
对于没有参数的宏,处理很简单,直接替换到源码就好了。
#define N 10
#define six 2+4
#define print printf("打印的值为:");
print //这里我不加分号,在宏定义里加,目的是让宏定义的文本替换更形象
printf("%d",N*six);
所以上述打印的值是多少呢?编译器把宏名称替换进去后,是这样的
printf("打印的值为:");
printf("%d",10*2+4);
可以看到,打印出来的值是24,而不是60,因为它是单纯文本替换,不计算,所以使用宏时要加上括号。
#define N 10
#define six (2+4)
printf("%d",N*six);
这样才能打印出60。
printf("%d",10*(2+4));
带参数的宏
前面最大值宏函数#define max(a,b) (a>b? a:b)
就是带了参数的宏。这里的替换文本也加了括号,是不是随意使用都没有问题呢?不是!
#define max(a,b) (a>b? a:b)
max(3,4==4);
在替换时,a
和b
是形参,3
,4==4(1)
是实参,参数之间用逗号隔开宏名称和括号之间不能有空格,否则就成为不带参数的宏,把(a,b) (a>b? a:b)
替换进去了。
上面代码我们期望返回的是3,因为b=(4==4)
的值是1,3大于1,但其实返回的是1。我们来替换一下,形参替换为实参,宏名替换为其他部分。
(3>4==4? 3:4==4)
因为>
和==
优先级相同,所以运算从左往右,因此逻辑表达式值为0,返回1即4==4
。
所以平时使用宏代码时,一定要注意,因为很容易出错。上述代码应该改为:
#define max(a,b) ((a)>(b)? (a):(b))
max(3,4==4);
每个形参都加括号,这样才能到达我们的目的。
对于宏还有几点注意:
- 宏定义中反斜杠的作用:对于比较长的替换文本,需要换行时应加入反斜杠,然后续写后面的内容。其中函数内代码换行也是加入反斜杠的,但是由于不用加也可以,为了代码美观,所以函数内单条一般不加反斜杠,直接换行。但是函数外则必须加入反斜杠换行才能进行续写。
2. 函数和宏函数的区别:我们说了宏只是文本替换,不做计算,虽然函数和带参数的宏用法类似,但是函数的操作不一样,它涉及到参数传递(将实参值赋值给形参)、函数调用和函数返回操作(入栈出栈)、返回值的传递,所以宏函数必然是要比函数的效率高的。
3. 宏的作用域:
你无法再次使用 #define
命令重新定义一个已经被定义为宏的标识符,除非重新定义所使用的替换文本与已经被定义的替换文本完全相同。如果该宏具有形参,重新定义的形参名称也必须与已定义形参名称的一样。
如果想改变一个宏的内容,必须首先使用下面的命令取消现在的定义:
#undef 宏名称
执行上面的命令之后,标识符“宏名称”可以再次在新的宏定义中使用。如果上面指定的标识符并非一个已定义的宏名称,那么预处理器会忽略这个 #undef
命令。
标准库中的多个函数名称也被定义成了宏。如果想直接调用这些函数,而不是调用同名称的宏,可以使用#undef
命令取消对这些宏的定义。即使准备取消定义的宏是带有参数的,也不需要在 #undef
命令中指定参数列表。如下例所示:
#include <ctype.h>
#undef isdigit // 移除任何使用该名称的宏定义
/* ... */
if ( isdigit(c) ) // 调用函数isdigit()
/* ... */
当某个宏首次遇到它的 #undef
命令时,它的作用域就会结束。如果没有关于该宏的 #undef
命令,那么它的作用域在该翻译单元结束时终止。
其他关于带参数的宏的用法,如可选参数、字符串化运算符(带#号)、 记号粘贴运算符等,参考文献1
参考文献:
标签:函数,定义,C语言,参数,文本,替换,define From: https://www.cnblogs.com/gofan-SiTu/p/17707964.html