C 预处理运算符“##&引用;
在学习“预处理器运算符”时,我在一本书中找到了一个定义:C 预处理运算符“##&引用;,c,c-preprocessor,preprocessor-directive,C,C Preprocessor,Preprocessor Directive,在学习“预处理器运算符”时,我在一本书中找到了一个定义: #定义CONCAT(x,y)x##y 调用CONCAT(a,b)将给出所需的输出ab。但是CONCAT(a,CONCAT(b,c))不会给出abc而是给出奇数输出 书中解释说,替换列表中的##前面或后面的宏参数在替换时不会展开。因此CONCAT(a,CONCAT(b,c))展开为acontact(b,c),无法进一步展开,因为没有名为acontat的宏。 好的,我明白了,但书中进一步提到,这个问题可以通过定义第二个宏来解决,该宏只调用第一
#定义CONCAT(x,y)x##y
调用CONCAT(a,b)将给出所需的输出ab
。但是CONCAT(a,CONCAT(b,c))
不会给出abc
而是给出奇数输出
书中解释说,替换列表中的##
前面或后面的宏参数在替换时不会展开。因此CONCAT(a,CONCAT(b,c))
展开为acontact(b,c)
,无法进一步展开,因为没有名为acontat
的宏。
好的,我明白了,但书中进一步提到,这个问题可以通过定义第二个宏来解决,该宏只调用第一个宏。范例
#定义CONCAT2(x,y)CONCAT(x,y)
编写CONCAT2(a,CONCAT2(b,c))
现在可以生成所需的列表abc
但是怎么做呢?我认为CONCAT2(a,CONCAT2(b,c))
将被CONCAT2(a,CONCAT2(b,c))
取代,后者进一步扩展到acocat2(b,c)
。现在没有名为acocat2
的宏,就像第一种情况一样,那么所需的输出是如何产生的呢
这证明了CONCAT2(a,CONCAT2(b,c))
工作正常。
确保编译器不会显示任何错误。除了用于使用getch()函数的警告。如果您有
#define CONCAT(x,y) x##y
#define CONCAT2(x,y) CONCAT(x,y)
然后当预处理器看到
CONCAT(a,CONCAT(b,c))
CONCAT2(a,CONCAT2(b,c))
CONCAT2(a,CONCAT(b,c))
CONCAT(a,CONCAT2(b,c))
它知道CONCAT(x,y)的替换列表是x##y,因此它将用a替换x,用CONCAT(b,c)替换y。唯一的问题是,在替换之前,它会扩展到a和/或CONCAT(b,c)a不是宏,因此无法展开,在替换列表x###y中,y前面有###,因此无法展开参数CONCAT(b,c)。因此,替换是在不展开的情况下完成的,替换列表变成了一个###CONCAT(b,c),然后在检查更多宏之前,它会处理##,替换列表变成acocat(b,c)
如果预处理器看到
CONCAT(a,CONCAT(b,c))
CONCAT2(a,CONCAT2(b,c))
CONCAT2(a,CONCAT(b,c))
CONCAT(a,CONCAT2(b,c))
它知道CONCAT2(x,y)的替换列表是CONCAT(x,y),因此它将用a替换x,用CONCAT2(b,c)替换y。唯一的问题是,在替换之前,它是否会扩展a和/或CONCAT2(b,c)a不是宏,因此无法展开,在替换列表CONCAT(x,y)中,y前面没有#或##,后面也没有##,因此在替换之前,CONCAT 2(b,c)完全展开。因此,CONCAT2(b,c)被扩展为CONCAT(b,c),它被扩展为b##c,不可能进一步扩展,因此y被b##c替换。替换列表x###y变成a##b##c,或者变成ab##c,然后变成abc,或者变成a##bc,然后变成abc
如果预处理器看到
CONCAT(a,CONCAT(b,c))
CONCAT2(a,CONCAT2(b,c))
CONCAT2(a,CONCAT(b,c))
CONCAT(a,CONCAT2(b,c))
它知道CONCAT2(x,y)的替换列表是CONCAT(x,y),因此它将用a替换x,用CONCAT(b,c)替换y。唯一的问题是,在替换之前,它会扩展到a和/或CONCAT(b,c)a不是宏,因此无法展开,在替换列表CONCAT(x,y)中,y前面没有#或##,后面也没有##,因此在替换之前,CONCAT(b,c)完全展开。因此,CONCAT(b,c)被扩展到b##c,不可能进一步扩展,因此y被b##c替换,替换列表x#y变成a#b#c,或者变成ab#c,然后变成abc,或者变成a#bc,然后变成abc
如果预处理器看到
CONCAT(a,CONCAT(b,c))
CONCAT2(a,CONCAT2(b,c))
CONCAT2(a,CONCAT(b,c))
CONCAT(a,CONCAT2(b,c))
它知道CONCAT(x,y)的替换列表是x##y,因此它将用a替换x,用CONCAT2(b,c)替换y。唯一的问题是,在替换之前,它是否会扩展a和/或CONCAT2(b,c)a不是宏,因此无法展开,在替换列表x###y中,y前面有###,因此不会展开参数CONCAT2(b,c)。因此,替换是在不展开的情况下完成的,替换列表变成了一个###CONCAT2(b,c),然后在检查更多宏之前,它会处理##,替换列表变成一个cat2(b,c)
你可能会这么想
#define CONCAT2(x,y) CONCAT(x,y)
意味着
CONCAT2(x,y)应与CONCAT(x,y)相同
但请记住:
每个问题请回答一个问题。因为这两个问题都与##运算符有关,所以我把它们放在一起。我是否应该将另一个问题作为不同的问题发布?是的,理想情况下,将第二个问题移动到一个新问题中,只留下第一个问题。
用一些例子来说明。
实际上,学习它的最简单方法就是玩它。或者读一些好的技巧,比如,很好的解释,斯图尔特·利特尔。