2017-07-28 139 views
1

我很难理解C预处理器在以下上下文中如何应用重写规则。我有以下宏:C预处理器宏扩展

#define _A(x) "A" _##x 
#define _B(x) "B" _##x 
#define X(x) _##x 

的想法是,这些宏使用的连接来创建一个新的表达,其本身可以是一个宏观 - 如果一个宏,我想这将扩大:现在

,下面的扩展,就像我期望:

X(x)  expands to _x 
X(A(x)) expands to "A" _x 
X(A(B(x))) expands to "A" "B" _x 

然而,一旦同宏多次使用,扩展停止:

X(A(A(x)))  expands to "A" _A(x), expected "A" "A" _x 
X(B(B(x)))  expands to "B" _B(x), expected "B" "B" _x 
X(A(B(A(x)))) expands to "A" "B" _A(x), expected "A" "B" "A" _x 
X(A(B(A(B(x))))) expands to "A" "B" _A(B(x)), expected "A" "B" "A" "B" _x 

我猜这里有某种“只能扩展同名宏”的规则?我能做些什么来让宏按我想要的方式扩展吗?

+1

这是因为您使用'##'运算符,它不评估宏;这是[嵌套宏扩展](https://stackoverflow.com/questions/31610231/nested-macro-expansion) –

+1

或[如何评估嵌套的预处理器宏](https:// stackoverflow。com/questions/13074432/how-to-evaluate-an-nested-preprocessor-macro) –

+0

也许我的大脑工作不正常,但我不明白这些问题是如何重复的。在你关联的问题中,问题是首先扩展宏,然后再连接。我想完全相反:先连接然后展开。另外,至少有一些扩展正在发生,或者我发布的示例根本不会扩展(例如,我们会得到X(A(x)) - _A(x),但是_A(x)显然会扩展) – MrMobster

回答

3

C99草案说,有没有在宏展开允许递归:

6.10.3.4重新扫描和再替换

  1. 替换列表中的所有参数后已经取代和 ###处理已完成,所有地标标记预处理标记都将被删除。然后重新扫描得到的预处理令牌序列 以及源文件的所有后续预处理令牌,以取代更多的宏名称。
  2. 如果扫描 替换列表(不包括源文件的 预处理标记的其余部分)的过程中发现被替换的宏 名,且未被替换。此外,如果任何 嵌套替换遇到正被替换的宏的名称,则不会替换它 。这些未替换的宏名称预处理 令牌不再可用于进一步替换,即使它们在其中宏名称 预处理令牌本应已被替换的上下文中稍后(重新)检查过时(重新)检查。

所以X(A(A(x)))扩展到"A" _A(x),但扩张本身不是扩大,如您所见。

+0

Bah its its what what ... ... ... I I I I I I I I I I I I I I I I I I I I I I I I I I :) – MrMobster

+0

我不知道有什么办法来得到你想要的效果 - 对不起! –

+1

@MrMobster规避预处理器的最简单方法是使用其他预处理器。看看M4处理器,例如http://mbreen.com/m4.html –

2

当我想要制定宏观扩展时,我通常会使用这个图,我使用标准的第6.10.3节构建这个图。希望它可以帮助...

enter image description here

由于托比已经提到的,嵌套宏不会递归扩展。

+0

谢谢,这是非常有用的! – MrMobster

+0

......但错了。在确定是否的路径之后,块表示“如果嵌套替换遇到宏的名称被替换,它不会被替换以避免递归”。这是指蓝色的油漆;但在重新扫描和进一步更换期间适用蓝色涂料(6.10.3.4);并且该块正在描述不带有这种限制的参数替换(6.10.3.1)。 –

+0

糟糕。我必须检查一下!在平均时间删除答案 – Jimbo