C语言中,在宏里面使用’#’和’##’有它非常神奇的作用。在宏定义的替换的过程中,#号可以作为一个预处理运算符,把宏参数转换为字符串。##运算符则可以把两个宏参数组合在一起。下面就来说说具体的用法。
1、一般用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起。
下面的代码是演示代码:
#include <stdio.h>
#define STRING(s) #s
#define CONNECT(a, b) (int)(a##e##b)
int main(void)
{
// 输出字符串"abcdefg"
printf("string:%s\r\n", STRING(abcdefg));
// 2e3输出:2000
printf("connect:%d\r\n", CONNECT(2,3));
return 0;
}
运行结果如下图:
2、当宏参数是另一个宏的时候
需要注意的是:凡是宏定义里有用'#'或'##'的地方,宏参数是不会再展开。
(1)、非’#’和’##’的情况
#include <stdio.h>
#define TOW (2)
#define MUL(a,b) (a*b)
int main(void)
{
printf("%d*%d=%d\r\n", TOW, TOW, MUL(TOW,TOW));
return 0;
}
上面代码中打印那行的宏会被展开为:
printf("%d*%d=%d\r\n", (2), (2), ((2)*(2)));
(2)、当有'#'或'##'的时候
#include <stdio.h>
#include <limits.h>
#define A (2)
#define STR(s) #s
#define CONS(a,b) (int)(a##e##b)
int main(void)
{
// INT_MAX 这行会被展开为:printf("int max: %s\r\n", "INT_MAX");
printf("int max: %s\r\n", STR(INT_MAX));
// 这一行会被展开为:printf("%s\r\n", (int)(AeA));
printf("%s\r\n", CONS(A, A));
return 0;
}
上面的代码在编译时会失败,INT_MAX和A都不会再被展开,然而解决这个问题的方法也很简单。加多一层中间转换宏。加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏(_STR
)就能得到正确的宏参数。
#include <stdio.h>
#include <limits.h>
#define A 2
#define _STR(s) #s
#define STR(s) _STR(s) // 转换宏
#define _CONS(a,b) (int)(a##e##b)
#define CONS(a,b) _CONS(a,b) // 转换宏
int main(void)
{
// INT_MAX,int型的最大值,为一个变量
printf("int max: %s\r\n", STR(INT_MAX));
printf("CONS(A, A):%d\r\n", CONS(A, A));
return 0;
}
其中代码:
printf("int max: %s\r\n", STR(INT_MAX));
输出为:int max: 2147483647
,STR(INT_MAX)
---> _STR(2147483647)
然后再转换成字符串。
第二个输出代码:
printf("CONS(A, A):%d\r\n", CONS(A, A));
输出为:CONS(A, A):200
,CONS(A, A)
---> _CONS(2, 2)
---> int(2e2)
。
3、'#'和'##'的一些应用特例
(1)、合并匿名变量名
#include <stdio.h>
#define ___ANONYMOUS1(type,var,line) type var##line
#define __ANONYMOUS0(type, line) ___ANONYMOUS1(type, _anonymous, line)
#define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)
int main(void)
{
ANONYMOUS(static int);
_anonymous9 = 666;
printf("_anonymous9:%d\r\n", _anonymous9);
return 0;
}
上述代码:ANONYMOUS(static int);
最终展开为:static int _anonymous9; // 9表示该行行号;
,下面分析下具体的展开过程:
第一次展开:ANONYMOUS(static int);
---> __ANONYMOUS0(static int, __LINE__);
;
第二次展开:__ANONYMOUS0(static int, __LINE__);
---> ___ANONYMOUS1(static int, _anonymous, 9);
;
第三次展开:___ANONYMOUS1(static int, _anonymous, 9);
---> static int _anonymous9;
;
对于宏的展开过程,每次只能解开当前层的宏,所以__LINE__
在第二层才能被解开。
(2)、获取文件名
#include <stdio.h>
#define _GET_FILENAME(filename) #filename
#define GET_FILENAME(filename) _GET_FILENAME(filename)
int main(void)
{
char filename[] = GET_FILENAME(__FILE__);
printf("filename:%s\r\n", filename);
return 0;
}
当然了,上述的宏也可以获取__DATE__
,__LINE__
等宏实际对应的值,上面专门定义了一个数组来存储转换后的值,实际使用时是否定义数组可自行安排。
如果文中有什么问题欢迎指正,毕竟博主的水平有限。
如果这篇文章对你有帮助,记得点赞和关注博主就行了。
注:转载请注明出处,谢谢!