C语言宏代码 - #define with 2'##'

时间:2015-09-15 05:10:11

标签: c embedded c-preprocessor

我最近遇到过这个问题,无法找到支持文档或数据进行解释。这个问题被问到我,而且这个人不愿意分享答案。

#define BIT(A)       BIT_##A
#define PIN_0        0

“我们是否通过使用宏BIT(PIN_0)获得BIT_0?如果没有进行必要的更正?”

我不知道上述问题的答案?

1 个答案:

答案 0 :(得分:10)

#define BIT(A) BIT_##A

表示从其他两个单独的标记创建单个标记。如果不使用##(令牌连接运算符),您可能会尝试执行以下操作之一:

#define BIT(A) BIT_A
#define BIT(A) BIT_ A

第一个问题是,因为BIT_A已经是一个令牌,所以不会尝试将A与传递的参数匹配,并且您将获得字面扩展BIT_A无论你用什么作为论据:

BIT(42) -> BIT_A

第二个问题是,即使A是一个单独的令牌而 因此需要替换,最终的扩展一个令牌:

BIT(42) -> BIT_ 42

宏中的##采用A指定的,并将其附加到文字BIT_,形成一个令牌,例如,< / p>

BIT(7)    -> BIT_7
BIT(PIN0) -> BIT_PIN0, but see below if you want BIT_0

这涵盖在C11 6.10.3.3 The ## operator

  

...删除替换列表中的##预处理标记的每个实例(不是来自参数)并进行前面的预处理   token与以下预处理标记连接。

     

生成的令牌可用于进一步的宏替换。

现在,如果你想要一个将BIT_和另一个已经评估的宏连接在一起的宏到一个令牌中,你必须使用一些技巧来让它做初始化在串联之前宏替换

那是因为标准规定在常规宏替换之前执行串联,这就是需要这种技巧的原因。你有什么问题:

#define PIN_0  0
#define BIT(A) BIT_##A

##的{​​{1}}扩展最初会产生标记BIT(PIN0)。现在,虽然这可以进行进一步的宏替换,但是单个令牌实际上没有宏替换,所以它保持原样。

要解决这个问题,你必须使用间接级别强制预处理器在BIT_PIN0之前进行常规宏替换:

##

上面显示的这一系列宏经历了许多阶段:

#define CONCAT(x,y) x ## y
#define PIN0 0
#define BIT(A) CONCAT(BIT_,A)