C语言宏定义小结
来源:互联网 发布:网络上个人信息 编辑:程序博客网 时间:2024/06/13 06:46
在C语言中,宏定义的形式如下:
#define name replacement-text
这是最简单的一种宏替换——后续所有出现name
的地方都会被替换成replacement-text
。#define
指令中的name
与普通变量名的命名方式相同,而replacement-text
可以是任意的字符串。如果一个宏定义比较长,可以在待续行的末尾加上一个反斜杠\
。就像下面这样:
#define DO_LOOP do{\ statements;\ }while(1)
#define
指令定义的name
作用域从定义处开始,直到被编译的源文件末尾处结束。宏定义的替换只针对对token
,对括在引号中的字符串不起作用。例如以下代码中的printf
函数仍然会打印出YES而不是123。
#define YES 123 printf("YES");
宏定义也可以带参数,这样可以根据不同的宏调用使用不同的replacement-text
。例如,下列宏定义定义了一个宏MAX,用来返回A和B之间的较大者:
#define MAX(A,B) ((A) > (B) ? (A) : (B))
宏调用直接将replacement-text
插入到代码中,形式参数A和B的每一次出现都会被替换成对应的实际参数。因此,语句:
x = MAX(a + b, c + d);
将会被替换成下列形式:
x = ((a + b) > (c + d) ? (a + b) : (c + d));
我们可以看到,宏MAX的展开式存在一些缺陷,作为参数的表达式要被重复计算两次,在上例中a + b和c + d均被计算了两次。如果表达式存在某些副作用,比如含有自增运算符或输入输出,那么会出现不正确的情况:
x = MAX(i++, j--);
它将对第一个参数做两次自增运算而对第二个参数做两次自减运算,这将会导致结果错误。同时还要注意,适当的使用圆括号来保证运算次序的正确性。由于宏调用是文本替换,替换后代码的运行结果和期望的运行结果可能会有所差异。例如以下代码:
#define MAXN 1000 + 5 int arr[MAXN * 4];
代码的期望运行结果是申请到一个能够容纳约4000个有符号整数的数组,但是实际运行结果是只申请到一个能够容纳1020个有符号整数的数组,访问下标大于等于1020的元素将会出现数组越界的错误。这是因为宏调用直接将MAXN替换为1000 + 5,又由于乘法的优先级大于加法,所以导致只申请到了能容纳1020个元素的整型数组。
对于带有参数的宏,在其replacement-text
中,以#为前缀的参数将会扩展为由实参替换该参数的带引号的字符串。例如:
#define dprintf(expr) printf(#expr " = %g\n", expr)
使用语句
dprintf(x / y);
调用该宏时,该宏将会被扩展为:
printf("x / y" " = %g\n", x / y);
其中的字符串被连接,等价于:
printf("x / y = %g\n", x / y);
在实际参数中,每个双引号"
被替换成\"
,反斜杠\
将被替换成\\
,因此替换后的字符串是合法的字符串常量。
预处理器运算符##
将为宏扩展提供一种连接实参的手段。如果replacement-text
中的参数与##
相邻,那么该参数将会被实参替换,##
与前后的空白符将被删除。例如,下面的宏PASTE用于连接两个参数:
#define PASTE(FRONT, BACK) FRONT ## BACK
因此,宏调用PASTE(hello,world)将建立记号helloworld。
对于有参数的宏,如果它的某个实参也是一个宏,且该实参紧临#
和##
,那么该实参不会进行宏扩展。例如:
#define STR(X) #X #define XSTR(X) STR(X) #define OP plus char* opname1 = STR(OP); char* opname2 = XSTR(OP);
这段代码把opname1置为”OP”而把opname2置为”plus”。我们知道,符号#
会立即字符串化紧随其后的参数。对于opname1来说,参数OP直接被字符串化,不再进行扩展;而对于opname2来说,由宏XSTR扩展它的参数,然后宏STR再对plus进行字符串化。
另一个关于符号##
的例子如下所示:
#define CAT(X, Y) X ## Y #define XCAT(X, Y) CAT(X, Y) int var1 = CAT(1, 2); int var2 = CAT(CAT(1, 2), 3); int var3 = XCAT(XCAT(1, 2), 3);
上面的代码将12赋值给var1,将123赋值给var3,var2所在的那行代码并不能正确执行。这是因为符号##
阻止了外层宏调用对其参数的扩展。而由于宏XCAT本身不含有符号##
,所以var3可以被正确赋值。
参考资料:
[1]Brain W. Kernighan and Dennis M. Ritchie, The C Programming Language, Second Edition, Prentice Hall, 1988
[2]Steve Summit, 《你必须知道的495个C语言问题》, 第二版, 北京 : 人民邮电出版社, 2016
- C语言宏定义小结
- C语言宏定义小结
- C语言宏定义小结
- C语言宏定义的使用小结
- C语言宏定义作用、使用方法小结
- C 宏定义小结
- C语言宏定义作用、使用方法小结(2)
- C语言宏定义作用、使用方法小结(1)
- C语言常量定义方法小结
- C宏定义的小结
- C宏定义的小结
- c语言宏定义
- C语言宏定义
- c语言宏定义
- c语言宏定义
- C语言宏定义
- c 语言宏定义
- C语言宏定义
- 国内可用的API合集
- 删除对象的属性 delete的用法
- 基于HTC vive 的 VR场景遍历及环境互动项目规划
- 每天一个小算法之Shell排序(希尔排序)
- 项目实训第二周2
- C语言宏定义小结
- PHPExcel自动导入数据到数据库
- 欢迎使用CSDN-markdown编辑器
- Android Binder Analysis(3)
- android surface
- 1.遇到的问题
- HDU3427-Clickomania
- swing 之FlowLayout 实现自动换行和滚动条添加
- AI和机器学习发展历程