C/C++ macro string concatenation

#define STR1      "s"
#define STR2      "1"
#define STR3      STR1 ## STR2

Is it possible to concatenate STR1 and STR2, to "s1"? You can do this by passing args to another Macro function. But is there a direct way?

262731 次浏览

如果它们都是字符串,你可以这样做:

#define STR3 STR1 STR2

这种情况随后扩大到:

#define STR3 "s" "1"

在 C 语言中,使用空格分隔两个字符串与使用单个字符串 "s1"完全等效。

对于字符串文字,您不需要这种解决方案,因为它们是在语言级别上连接的,而且它无论如何也不会工作,因为“ s”“1”不是一个有效的预处理器令牌。

[编辑: 作为对下面不正确的“仅供记录”评论的回应,不幸地收到了几个赞,我将重申上述声明,并观察到程序片段

#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")

从 gcc: Error: 粘贴“ s”和“1”不会提供有效的预处理令牌的预处理阶段生成此错误消息

]

但是,对于一般的标记粘贴,请尝试这样做:

/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B


/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)

然后,例如,PPCAT_NX(s, 1)PPCAT(s, 1)都产生标识符 s1,除非 s被定义为宏,在这种情况下,PPCAT(s, 1)产生 <macro value of s>1

继续讨论主题的是这些宏:

/*
* Turn A into a string literal without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define STRINGIZE_NX(A) #A


/*
* Turn A into a string literal after macro-expanding it.
*/
#define STRINGIZE(A) STRINGIZE_NX(A)

然后,

#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"

相比之下,

STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"


#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"

提示: 上面的 STRINGIZE宏很酷,但是如果你犯了一个错误,它的参数不是一个宏-你在名称中有一个输入错误,或者忘记了 #include头文件-然后编译器会很高兴地将所谓的宏名称放入字符串中,没有错误。

如果您希望 STRINGIZE的参数始终是一个具有正常 C 值的宏,那么

#define STRINGIZE(A) ((A),STRINGIZE_NX(A))

将展开它一次并检查它的有效性,丢弃它,然后再将它展开为一个字符串。

我花了一段时间才弄明白为什么 STRINGIZE(ENOENT)最终变成了 "ENOENT"而不是 "2"... 我没有包括 errno.h