CC++:宏定义中的#与##

xiaoxiao2021-02-27  484

C/C++:宏定义中的#与##

测试环境:CentOS

[mytmp@localhost ~]$ uname -a Linux localhost.localdomain 2.6.18-371.el5 #1 SMP Thu Sep 5 21:21:44 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux [mytmp@localhost ~]$ gcc --version gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)

在宏定义中,使用#可以将参数变成一个字符串,使用##可以将参数粘合在一起。

#include <stdio.h> #include <stdlib.h> #define NUM(n) #n #define MYPASTE(n, m) n##01##m int main() { printf("%d\n", 10); printf("%s\n", NUM(11)); printf("%d\n", MYPASTE(2, 7)); return 0; } [mytmp@localhost ~]$ gcc -E main.c …… int main() { printf("%d\n", 10); printf("%s\n", "11"); printf("%d\n", 2017); return 0; } 输出如下:

[mytmp@localhost ~]$ ./main 10 11 2017 可以看到#起到了将一个数字转变为字符串的功能;

##可将多部分直接黏连在一起。

#以及##出现在宏定义中的展开问题:

#include <stdio.h> #include <stdlib.h> #define NUM 6 #define S_NUM(num) #num #define PASTE_NUM(a, b) a##b int main() { printf("%s\n", S_NUM(NUM)); printf("%d\n", PASTE_NUM(NUM, NUM)); return 0; } [mytmp@localhost ~]$ gcc -E main.c

预编译输出如下:

…… int main() { printf("%s\n", "NUM"); printf("%d\n", NUMNUM); return 0; } 这个例子什么意思呢?

现在有个宏是NUM,当它传入到另外一个宏:S_NUM中时,会不会展开。

显然是不会的,因为在S_NUM的定义中使用了#,即后半部分:#num。

到最后就是#NUM,NUM不会被替换为对应的数字(6),不会展开。

简单点来说:#MACRO时,MACRO是一个宏,MACRO不会展开。

##同理。

##可以看到最后直接是符号级别的黏连在一起了,并没有展开为66(NUM##NUM-》NUM)。

有没有展开的办法?--》多使用一层宏来展开:

#include <stdio.h> #include <stdlib.h> #define NUM 6 #define S_NUM(num) #num #define S_NUM1(num) S_NUM(num) #define PASTE_NUM(a, b) a##b #define PASTE_NUM1(a, b) PASTE_NUM(a, b) int main() { printf("%s\n", S_NUM1(NUM)); printf("%d\n", PASTE_NUM1(NUM, NUM)); return 0; } 预编译之后为:

…… int main() { printf("%s\n", "6"); printf("%d\n", 66); return 0; } 输出结果为:

[mytmp@localhost ~]$ gcc -o main main.c [mytmp@localhost ~]$ ./main 6 66 很明显,多加了一层展开了宏。

有可能是这么一个流程:首先遇到了S_NUM1(NUM),看了下S_NUM1的宏定义,没有啥#开头的,那么就用NUM替换掉S_NUM1,这样就是S_NUM(6),接下来发现是#num,再将其转换为字符串。

核心的是:增加的那一层,没有#/##,使得宏参数展开,继而不会产生#/##出现展不开的问题。

另一个不再赘述。

现在我们看一个例子。

有这么一个宏:

#include <stdio.h> #include <stdlib.h> #define AT __FILE__":"__LINE__ int main() { printf("%s\n", AT); return 0; } 本意是输出__FILE__以及__LINE__,但是实际预编译后为:

int main() { printf("%s\n", "main.c"":"8); return 0; } 究其原因,是__LINE__并不是字符串,而是个数字。

呀,我可以使用#来将其转换下:

#define AT __FILE__":"#__LINE__ 预编译是:

printf("%s\n", "main.c"":"#8); 换个宏定义试试:

#include <stdio.h> #include <stdlib.h> #define CONVERT(x) #x #define AT __FILE__":"CONVERT(__LINE__) int main() { printf("%s\n", AT); return 0; } 预编译后是:

int main() { printf("%s\n", "main.c"":""__LINE__"); return 0; } 结果并不奇怪,仔细想想,宏展开了嘛?当然没有。我们之前说怎么展开来着?

增加一层“宏参数展开层”。

#include <stdio.h> #include <stdlib.h> #define CONVERT(x) #x #define CONVERT1(x) CONVERT(x) #define AT __FILE__":"CONVERT1(__LINE__) int main() { printf("%s\n", AT); return 0; } 预编译之后如下:

int main() { printf("%s\n", "main.c"":""10"); return 0; } 输出结果如下:

[mytmp@localhost ~]$ ./main main.c:10

成功。

参考资料:

1.http://blog.csdn.net/tomtc123/article/details/8875468

2.http://www.cnblogs.com/lzjsky/archive/2010/11/24/1886690.html

3.http://www.blogjava.net/cxzforever/articles/356583.html

转载请注明原文地址: https://www.6miu.com/read-555.html

最新回复(0)