使用##和__LINE__创建C宏(使用定位宏进行标记连接)

DD.*_*DD. 103 c macros concatenation token

我想创建一个C宏,它创建一个名称基于行号的函数.我以为我可以做类似的事情(真正的函数会在括号内有声明):

#define UNIQUE static void Unique_##__LINE__(void) {}
Run Code Online (Sandbox Code Playgroud)

我希望将扩展到以下内容:

static void Unique_23(void) {}
Run Code Online (Sandbox Code Playgroud)

这不起作用.使用令牌连接,定位宏按字面处理,最终扩展为:

static void Unique___LINE__(void) {}
Run Code Online (Sandbox Code Playgroud)

这可能吗?

(是的,无论这看起来多么无用,我都有一个真正的理由要这样做).

Ada*_*eld 169

问题是当你有一个宏替换时,如果字符串化操作符#和令牌粘贴操作符##都没有应用于它,预处理器将只递归地扩展宏.因此,您必须使用一些额外的间接层,您可以使用带有递归扩展参数的token-pasting运算符:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}
Run Code Online (Sandbox Code Playgroud)

然后,__LINE__在扩展期间扩展到行号UNIQUE(因为它不涉及任何#或者##),然后在扩展期间发生令牌粘贴TOKENPASTE.

还应该注意的是,还有__COUNTER__宏,每次计算时都会扩展为一个新的整数,以防你需要UNIQUE在同一行上有多个宏的实例化.注意:__COUNTER__MS Visual Studio,GCC(自V4.3起)和Clang支持,但不是标准C.

  • 我担心这不适用于GNU cpp.TOKENPASTE使用__LINE__作为文字.TOKENPASTE(Unique_,__LINE__)扩展为Unique___LINE__ (3认同)
  • @DD:噢,现在修好了.它需要2层间接,而不是1层. (3认同)
  • 关于为什么需要 2 个间接级别的任何解释?我只试过一个,没有 # 和 ##,并且没有在 VS2017 上扩展它。显然 GCC 也是如此。但是如果你添加第二级间接,那么它确实会扩展。魔法? (3认同)
  • 根据http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx,任何尝试__COUNTER__的人都需要额外的信息,这是微软特有的一个宏. (2认同)