C 无与伦比的括号宏怪诞

C 无与伦比的括号宏怪诞,c,macros,c-preprocessor,C,Macros,C Preprocessor,根据C99规则预处理以下3行的正确输出是什么 #define y(x) x #define x(a) y(a x(1) x(2))) 顺便说一句,linux下的cpp会产生一条错误消息,但我不明白为什么答案不简单 1 2 假设cpp是正确的,而我错了,我将非常感谢您的解释 宏展开后,在结果文本中展开宏的尝试会在与周围文本组合之前单独进行。因此,尝试展开y(1时会出现此错误。实际上,很难指定宏展开以您想要的方式工作,同时仍满足许多其他必需的行为(例如缺少无限递归).找到宏后,预处理器将收集宏的

根据C99规则预处理以下3行的正确输出是什么

#define y(x) x
#define x(a) y(a
x(1) x(2)))
顺便说一句,linux下的cpp会产生一条错误消息,但我不明白为什么答案不简单

1 2

假设cpp是正确的,而我错了,我将非常感谢您的解释

宏展开后,在结果文本中展开宏的尝试会在与周围文本组合之前单独进行。因此,尝试展开y(1时会出现此错误。实际上,很难指定宏展开以您想要的方式工作,同时仍满足许多其他必需的行为(例如缺少无限递归).

找到宏后,预处理器将收集宏的参数,然后在展开第一个宏之前,单独扫描每个宏参数,以查找要在参数内展开的其他宏:

6.10.3.1参数替换

在确定调用函数(如宏)的参数后, 发生参数替换。替换列表中的参数,除非前面有 由#或#####预处理令牌或后跟###预处理令牌(见下文)表示 在包含在其中的所有宏被删除后,替换为相应的参数 在被替换之前,每个参数的预处理标记都是 完全替换宏,就好像它们构成了预处理文件的其余部分;没有其他宏 预处理令牌可用

在这个具体的例子中,它看到了
x(1)
,并对其进行了扩展,给出了

y(1 x(2)))
然后,它用参数
1x(2)
标识宏调用
y(1x(2))
,并为宏的扩展预先设置参数。在该参数中,它找到扩展为
y(2x
)的
x(2)
,然后由于没有
,触发错误
用于
y
宏。请注意,此时它仍然希望扩展第一个
y
宏的参数,因此它单独查看它,而不考虑输入文件的其余部分,这与6.10.3.4的扩展不同


现在有一个问题是,这是否真的应该是一个错误,或者预处理器是否应该将此
y(2
序列视为根本不是宏调用,因为没有“')。如果它执行后者,那么它会将该y调用扩展到
1y(2
,然后将与其余输入(
)组合
)并最终扩展到
1 2

错误消息是什么?cpp处理在C99下的错误消息,在Mac上对我来说很好,输出
1 2
.t.c:3:10:错误:调用宏“y”的未终止参数列表。如果它在您的系统上工作,可能是真正的linux cpp错误。展开宏后,在结果文本中展开宏的尝试会在与周围文本组合之前单独进行。"-c99标准中的相应措辞是什么?我这里只有一份c++11标准草案。它说了一些完全不同的内容:
然后重新扫描生成的预处理令牌序列,以及源文件的所有后续预处理令牌,以替换更多宏名。
是否有重要影响这两种语言之间的差异?C99中的文本类似:6.10.3.4:“然后,重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称。”我不清楚,但也许我的答案是错的,这确实是一个错误。非常感谢R..n.m.我倾向于一个错误,但GNU的人通常在标准一致性方面相当出色。@n.m:C99标准的最新版本(原始标准中合并了三个技术勘误)是的。啊。你当然是对的。当扩展参数“1 x(2)”时,我们在点击y后不会消耗额外的令牌(2。回答得很好。谢谢。我认为这应该是一个错误,没有任何问题-§6.10.3说函数的一个实例,比如宏名后跟
总是像宏一样调用函数。@caf:因为它没有明确地说这是一个错误,所以它可能被认为是未定义的,所以在这种情况下,实现可能会执行任何操作。