在学习“预处理程序运算符”时,我在书中发现了一个定义:
//Listen for app to POST Credential
app.post('/', async function(request, response) {
console.log('Request Body: ',request.body);
var Credential = request.body;
//Validate Credential
var userId = await validateCredential(Credential) //Waits until userId comes
//Get Authorization Token
var firebaseAuthToken = await getToken(userID) //waits until Token comes
//Return Token for POST Response
response.set('Content-Type','Text');
response.end(firebaseAuthToken);
});
调用#define CONCAT(x,y) x##y
可获得所需的输出CONCAT(a,b)
。但是ab
不会给出CONCAT(a,CONCAT(b,c))
而是给出奇数输出。
Book通过解释说,替换列表中没有扩展在替换列表中abc
之前或之后的宏参数。因此,##
扩展为CONCAT(a,CONCAT(b,c))
,由于没有名为aCONACT(b,c)
的宏,因此无法进一步扩展。
好的,我明白了,但本书还进一步提到,可以通过定义仅调用第一个宏的第二个宏来解决此问题。例子
aCONCAT
现在写#define CONCAT2(x,y) CONCAT(x,y)
可以得到所需的列表CONCAT2(a,CONCAT2(b,c))
。
但是如何?我认为abc
将被CONCAT2(a,CONCAT2 (b,c))
取代,而CONCAT(a,CONCAT2(b,c))
将进一步扩展为aCONCAT2(b,c)
。现在没有命名为aCONCAT2
的宏,就像在第一种情况下一样,那么期望的输出又如何呢?
这是CONCAT2(a,CONCAT2 (b,c))
正常工作的证明。
答案 0 :(得分:1)
如果有
#define CONCAT(x,y) x##y
#define CONCAT2(x,y) CONCAT(x,y)
然后当预处理程序看到
CONCAT(a,CONCAT(b,c))
它知道CONCAT(x,y)的替换列表是x ## y,因此它将用 a 和 y 替换 x 。 strong>和 CONCAT(b,c)。唯一的问题是,在替换之前,它会展开 a 和/或 CONCAT(b,c)吗? a 不是宏,因此无法扩展,并且在替换列表x ## y中,y之前是##,因此对参数CONCAT(b,c)不会进行扩展。因此,替换操作无需扩展即可完成,替换列表将变为a ## CONCAT(b,c),然后在检查更多宏之前,它将处理##,替换列表将变为aCONCAT(b,c)。>
如果预处理器看到
CONCAT2(a,CONCAT2(b,c))
它知道CONCAT2(x,y)的替换列表是CONCAT(x,y),因此它将用 a 和替换 x y 和 CONCAT2(b,c)。唯一的问题是,在替换之前,它会展开 a 和/或 CONCAT2(b,c)吗? a 不是宏,因此无法扩展,并且在替换列表CONCAT(x,y)中, y 之前不能带有#或##,也不能跟在后面##,因此 CONCAT2(b,c)在替换前已完全展开。因此, CONCAT2(b,c)扩展为CONCAT(b,c),后者扩展为b ## c,无法进一步扩展,因此将 y 替换为由b ## c。替换列表x ## y变成a ## b ## c,或者变成ab ## c,然后变成abc,或者变成a ## bc,然后变成abc。
如果预处理器看到
CONCAT2(a,CONCAT(b,c))
它知道CONCAT2(x,y)的替换列表是CONCAT(x,y),因此它将用 a 和替换 x y 和 CONCAT(b,c)。唯一的问题是,在替换之前,它会展开 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,CONCAT2(b,c))
它知道CONCAT(x,y)的替换列表是x ## y,因此它将用 a 和 y 替换 x 。 strong>和 CONCAT2(b,c)。唯一的问题是,在替换之前,它会展开 a 和/或 CONCAT2(b,c)吗? a 不是宏,因此无法扩展,并且在替换列表x ## y中,y之前是##,因此对参数CONCAT2(b,c)不会进行扩展。因此,替换操作无需扩展即可完成,替换列表变为a ## CONCAT2(b,c),然后在检查更多宏之前,它会处理##,替换列表变为aCONCAT2(b,c)。
您可能会认为
#define CONCAT2(x,y) CONCAT(x,y)
表示
CONCAT2(x,y)应该与CONCAT(x,y)相同
但请记住:
CONCAT(x,y)的替换列表是x ## y,并且因为x后面是##,y之前是##,所以当预处理程序看到CONCAT宏的实例时,它将替换前不展开与x或y对应的参数。但是,CONCAT2(x,y)的替换列表是CONCAT(x,y),替换中的x或y都不能以#或##开头或以##开头,因此当预处理器看到CONCAT2宏的实例时,它将在替换之前完全扩展参数中的所有宏。
参数的宏扩展(如果允许)在替换之前发生。因此在CONCAT2(a,CONCAT(b,c))中,在替换之前先扩展CONCAT(b,c)参数。所以我们得到CONCAT2(a,b ## c)而不是CONCAT(a,CONCAT(b,c))。