C/C++宏字符串连接

tvr*_*tvr 105 c c++ c-preprocessor

#define STR1      "s"
#define STR2      "1"
#define STR3      STR1 ## STR2
Run Code Online (Sandbox Code Playgroud)

是否有可能连接STR3 =="s1"?您可以通过将args传递给另一个宏函数来完成此操作.但是有直接的方法吗?

Sea*_*ean 140

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

#define STR3 STR1 STR2
Run Code Online (Sandbox Code Playgroud)

预处理器自动连接相邻的字符串.

编辑:

如下所述,它不是预处理器,而是执行串联的编译器.

  • 预处理器没有这样的东西.正确的C语言将相邻的字符串文字视为单个字符串文字. (43认同)
  • 技术上字符串连接在语言级别完成. (15认同)
  • 它不仅仅是技术性 - 你不能连接`L"a"和`"b"`来得到'L"ab"`,但你_can_连接`L"a"`和`L"b"`得到'L"ab"`. (7认同)
  • @Zythos - 您可能想发布一个单独的问题,其中包含一些有关您正在尝试做什么、您期望发生什么以及实际发生了什么的详细信息。 (2认同)

Jim*_*ter 102

你不需要那种字符串文字的解决方案,因为它们在语言级别连接,并且它无论如何都不会起作用,因为"s""1"不是有效的预处理器标记.但是,对于一般的令牌粘贴,请尝试以下方法:

#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")
Run Code Online (Sandbox Code Playgroud)

然后,例如,PPCAT_NX(s, 1)产生标识符PPCAT(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)
Run Code Online (Sandbox Code Playgroud)

然后,

/*
 * 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)
Run Code Online (Sandbox Code Playgroud)

  • 只是为了记录,`"s""1"`在C(和C++)中有效.它们是两个令牌(字符串文字),编译器将其自身连接并将威胁作为一个标记. (8认同)
  • @ mr5仔细阅读评论.作为宏参数传递的宏名称在传递之前不会展开.然而,它们在宏观体中得到了扩展.因此,如果A被定义为FRED,则STRINGIZE_NX(A)扩展为"A",但STRINGIZE(A)扩展为STRINGIZE_NX(FRED),扩展为"FRED". (8认同)
  • 你误解了我的评论和C语言.我说`s""1"不是有效的令牌 - 这是正确的; 正如你所说,它是*两个*代币.但是将它们与##一起使用将使它们成为单个*预处理令牌,而不是两个令牌,因此编译器不会进行连接,而是词法分析器会拒绝它们(语言需要诊断). (4认同)

Jor*_*own 24

提示:STRINGIZE上面的宏很酷,但如果你犯了一个错误并且它的参数不是一个宏 - 你的名字中有一个拼写错误,或者忘#include了头文件 - 那么编译器会愉快地将声称的宏名称放入字符串没有错误.

如果您打算将参数设置STRINGIZE为具有正常C值的宏,那么

#define STRINGIZE(A) ((A),STRINGIZE_NX(A))
Run Code Online (Sandbox Code Playgroud)

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

我花了一段时间才弄清楚为什么STRINGIZE(ENOENT)最终结束"ENOENT"而不是"2"...我没有包括在内errno.h.

  • 重要的观察,以及正确使用`,`运算符的+1.:) (2认同)
  • 字符串的内容应该是有效的 C 表达式没有什么特别的原因。如果你想这样做,我建议给它一个不同的名字,比如 STRINGIZE_EXPR。 (2认同)
  • 只是为了澄清自守的含义:使用原始的“STRINGIZE”定义,““ENOENT 的值是” STRINGIZE(ENOENT)”有效,而““ENOENT 的值是”STRINGIZE_EXPR(X)”会产生错误。 (2认同)