带有尾部注释的多行预处理宏

7

我想定义下面这个普通的宏:

#define MY_ENUM enum MyEnum{ \
    myVal0, \ //Describes this situation
    myVal2  \ //Describes that situation
}

令我惊讶的是,这个代码由于“error: stray ‘\’ in program”的原因而无法工作。即使在反斜杠后面加上一些空格,也会导致“warning: backslash and newline separated by space”。正如这个答案所指出的那样,反斜杠必须是行末的字符。这个答案指出,在处理注释之前会进行行拼接。选择这种顺序的原因对我来说完全没有意义;我唯一能想象到的原因是允许类似下面的多行注释:
//This is a comment which \
follows in the next line

这看起来非常危险,因为这样的话在尝试时可能会吞掉下一行上的任何代码。相反的顺序,即在拼接行之前用单个空格替换每个注释,听起来对我来说更明智。有人能解释一下为什么做出这个选择吗?

我可以通过以下方式解决我的原始问题:

#define MY_ENUM enum MyEnum{ \
    myVal1, /*Describes this situation*/ \
    myVal2  /*Describes that situation*/ \
}

我做这个笨拙的枚举宏定义的目的是,这个宏必须在c++和c之间共享(由于Qt,它绝对必须是一个类成员)。在我看来,定义这样的宏似乎是唯一的解决方案,但上述解决方法看起来很丑陋,我绝对不想让枚举没有注释。我是否错误地解决了这个问题?


3
请原谅我的幼稚,但为什么你需要一个枚举宏?我会将枚举定义放入头文件中并包含该头文件。 - Thomas Matthews
5
您已经描述了遇到的问题和解决方案。请使用 /*...*/ 注释。 - Pete Becker
1
这句话的意思是:听起来你是否想用非C语法编写C代码,因为这样看起来更好看...这有点奇怪。Translated text: 翻译后的文本为:这似乎是在询问您是否可以使用非C语法编写C代码,因为它看起来更漂亮...这有点奇怪。 - Dmitri
"...拼接发生在注释处理之前。这个顺序对我来说毫无意义;毕竟,预处理器是在评估 C/C++ 代码之前处理输入的。" - chux - Reinstate Monica
注释是 C 代码的一部分。它们作为空格。例如:-/*abc*/-a- -a 的代码是相同的,而不是 --a - chux - Reinstate Monica
显示剩余3条评论
2个回答

5
问题在于C预处理器在遇到\并继续时,只是添加了另一个换行符。
//注释中,您不能这样做。 \字符不被接受以继续注释(它应该显示为单行)。
解决方案是——正如您自己发现的那样——使用/* */注释风格。

2
首先进行行拼接,将整个宏定义(包括注释)放在一行上...因此第一个//注释掉了宏定义的其余部分。对于/* */注释,注释可以在行末之前关闭,这就是为什么该风格仍然有效的原因。 - Dmitri

1
要理解这种现象,您可能需要参考C标准(我相信C++在这方面与C类似)。特别是在“翻译阶段”部分(C11草案§5.1.1.2)中。
预处理器必须像从上到下执行的阶段一样行事(即在第二步完全完成后才执行第三步等)。
基本上,///* ... */注释在第三阶段被识别,即在尾随\处理之后执行(即第二阶段),这意味着它对它们是不可知的。换句话说,它将它们视为没有特殊含义的普通源文本。
  1. 每个反斜杠字符(\)紧跟着一个新行字符立即被删除,将物理源代码行拼接成逻辑源代码行。任何物理源代码行上的最后一个反斜杠符号才有资格成为这样一个拼接的一部分。

  2. 源文件被分解为预处理记号7)和空白字符序列(包括注释)。源文件不应以部分预处理记号或部分注释结束。每个注释都被一个空格字符替换。新行字符保留。除了新行字符之外的每个非空白字符序列是保留还是替换为一个空格字符,是由实现定义的。


我修改了问题文本以澄清我已经知道这是事实(请查看我在问题中提供的参考资料),我不明白的是为什么做出这个选择。 - Ayberk Özgür

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接