note - tips - c macro multi-level expansion
经常看到一个宏嵌套另一个宏的做法,却没深入了解过原因,正好抽空整理了一下,顺带记录。
c 语言宏定义多级展开
在预编译阶段展开宏定义,如果为多级宏定义,则一次只展开当前的宏,但涉及到 “#” 和 “##” 时不会展开,举例如下:
#define VERSION_DECAL 10
#define PREFIX_HEX 0x
#define TO_HEX(prefix, a) (prefix##a)
#define VERSION TO_HEX(PREFIX_HEX, VERSION_DECAL)
- VERSION -> TO_HEX(PREFIX_HEX, VERSION_DECAL);
- TO_HEX(PREFIX_HEX, VERSION_DECAL) -> (PREFIX_HEX##VERSION_DECAL);
- 导致输出 “PREFIX_HEXVERSION_DECAL” 错误。
此时可在 #define TO_HEX(prefix, a) (prefix##a)
之间加一层中间宏先展开再连接,例如:
#define VERSION_DECAL 10
#define PREFIX_HEX 0x
#define _TO_HEX(prefix, a) (prefix##a)
#define TO_HEX(prefix, a) _TO_HEX(prefix, a)
#define VERSION TO_HEX(PREFIX_HEX, VERSION_DECAL)
- VERSION -> TO_HEX(PREFIX_HEX, VERSION_DECAL);
- TO_HEX(PREFIX_HEX, VERSION_DECAL) -> _TO_HEX(0x, 10);
- _TO_HEX(0x, 10) -> (prefix##a)
- 导致输出 “0x10” 。
c 语言宏定义 tips
宏定义展开不会替换 “” 中间部分,即#define TO_STRING(a) "a"
此时不管TO_STRING(a)中的 a 是什么,最终都会替换为 “a”;
需要通过宏转为字符串,则需用到 “#”,如#define TO_STRING(a) #a
,此时可将对应的a转为字符串,但同样涉及到多级展开,此时 TO_STRING(a) 中必须为要转为的字符串,而不能是另一层宏,否则可参考上述添加中间宏先展开再连接。
问题(未解决,待续。。。)
按每次展开一级的理论,以下 demo 应该输出 “TO_HEX(PREFIX_HEX, VERSION_DECAL)”,但实际可以输出 “0x10”。
#include <stdio.h>
#define VERSION_DECAL 10
#define PREFIX_HEX 0x
#define _TO_HEX(prefix, a) (prefix##a)
#define TO_HEX(prefix, a) _TO_HEX(prefix, a)
#define VERSION TO_HEX(PREFIX_HEX, VERSION_DECAL)
#define _TO_STRING(a) #a
#define TO_STRING(a) _TO_STRING(a)
int main()
{
/* Write C code in this online editor and run it. */
printf("Hello, World! %s \n", TO_STRING(VERSION));
return 0;
}