单行注释宏导致gcc出错

3

atest.c

#define COMMENT /##/

int main()
{
   ...
   COMMENT int atest;
   ...
}

错误信息: atest.c:16:1: 错误: 将“/”和“/”粘贴在一起并不会产生有效的预处理标记 atest.c:在函数'main'中: atest.c:16: 错误: 在'/'标记之前期望表达式 虽然Microsoft C编译器对COMMENT宏很满意,但此处提示也无法工作。
有人能否给出解决方案或解释?谢谢。
3个回答

8
当您使用token粘贴运算符##时,合并两个操作数的结果必须是一个有效的预处理器标记。 //不是一个有效的预处理标记。预处理发生在删除注释后,因此不能在预处理阶段添加注释。

4

由于注释处理是在宏之前完成的,因此宏生成的注释不能被编译器识别。引用Ben Combee在您引用的文章中的回复:

我刚刚阅读了你在CUJ 2001年1月份发布的C/C++ Tip#5。提示的内容(将宏展开为注释)非常熟悉,因为我曾在Microsoft的一个头文件中看到过类似的方法。然而,该提示是非常不正确的。作者使用标记粘贴来构造注释开始序列。但是,根据C和C ++标准,这是无效的。在ISO C(1999)的第5.1.1.2节“翻译阶段”中,注释处理发生在第3阶段,其中预处理器识别标记和空格,并用空格替换注释。然后在第4阶段完成宏处理,并且这个阶段是引入这些新注释开始序列的阶段。在#4之后没有后续阶段,其中注释将被识别,因此符合规范的编译器最终会由于非法令牌而拒绝程序文本 - '//'. 1998年的C ++标准在第2.1节“翻译阶段[lex.phases]”中有类似的语言。一些编译器充分混合了阶段的顺序和处理,以允许此宏工作,Microsoft的Visual C ++ 6.0因其流行而显着。其他编译器,例如Metrowerks CodeWarrior C / C ++编译器(我在那里担任编译器工程师超过两年,直到现在的职业),遵循标准,并将拒绝在提示中显示的用法。谢谢,Ben Combee Lead Software Architect Veriprise Wireless http://www.veriprise.com 因此,本期刊物在发布此通知后如下:

我们希望提醒读者,此提示不具备可移植性,也许不应在生产代码中使用。


谢谢大家的解释。实际上,这个问题是在我对我的项目运行splint时出现的。splint在类似COMMENT的一行上失败了。然后我编写了atest.c并在gcc上测试了COMMENT。然而,让我惊讶的是,当我在上述atest.c上运行splint时,splint很高兴,并给出了消息“atest.c(16,13):变量atest已声明但未使用”。 - hmj

2

很抱歉我不知道如何做这个。

您可以使用命令cpp(c预处理器)对代码进行预处理,以查看发生了什么。 将您提供的代码通过cpp运行,得到以下结果:

int main()
{
a.c:5:1: error: pasting "/" and "/" does not give a valid preprocessing token
       / / int atest;
}

尝试中...
#define COMMENT /
#define SLASH(x) x/

SLASH(COMMENT)

导致

/ /

然而,尝试中...
#define TEST(y) y/
TEST(hello)

导致
hello/

通常像 // 这样的注释会被删除并替换为单个“注释令牌”,此步骤在预处理之前完成(当 # 指令发生时),因此即使您可以将注释放在那里,我怀疑它也不总是被识别(据我所知,标准并不保证它)。很抱歉我无法提供更多帮助。

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