首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么## (令牌粘贴)操作符不能用于C和C++中的注释?

为什么## (令牌粘贴)操作符不能用于C和C++中的注释?
EN

Stack Overflow用户
提问于 2020-01-12 13:06:51
回答 2查看 1.6K关注 0票数 3

为什么会发生以下错误?

代码语言:javascript
运行
复制
#include <iostream>

#define concatenate(t1, t2) t1 ## t2 // Concatenate token1 and token2

int main()
{
    int myVar = 22;
    std::cout << concatenate(my, Var); // Compiles fine and outputs the value of myVar

    concatenate(/, /) So I thought that this would be a comment but this is a compile-time error
    // error: pasting "/" and "/" does not give a valid preprocessing token

    return 0;
}

我认为concatenate(/, /)会告诉预处理器用//替换它,然后当它进一步分析时,整行将被解释为注释。

这个案子到底发生了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-12 13:30:09

这个答案适用于C,在C++中类似。

该示例与C11标准6.4.9p3中的示例完全相同。

代码语言:javascript
运行
复制
      #define glue(x,y) x##y
      glue(/,/) k();                     // syntax error, not comment

您所看到的错误:

错误:粘贴"/“和"/”不能提供有效的预处理令牌

因此,##的结果需要预处理令牌。简而言之,预处理令牌是标识符、预处理数字、字符串文本、标点符号等等。(另见gcc关于标记化的文档)。生成的//字符串不是预处理令牌,因此这里##的结果将不是预处理令牌。C标准6.10.3.3p3声明,如果##的结果“不是有效的预处理令牌,则行为是未定义的”。在这种情况下,您使用的编译器选择发出错误。它的工作方式将与下列不工作方式不同:

代码语言:javascript
运行
复制
concatenate(:, b) // error, `:b` is not a preprocessing token
concatenate(%, b) // error, `%b` is not a preprocessing token
// etc.

例如,可能来自另一边,例如%=是一个有效标记,标点符号。以下各点可以:

代码语言:javascript
运行
复制
concatenate(%, =)
concatenate(/, =)
concatenate(a /, = b)
concatenate(<, :)

无论如何,即使//是有效的预处理,在翻译阶段3中,注释被替换为单个空格,而预处理程序在删除注释后在翻译阶段4中执行,请参见C11翻译阶段。因此,即使它会导致//令牌,它也将是无效的,因为它在C中并不意味着任何东西(除了注释)。

票数 7
EN

Stack Overflow用户

发布于 2020-01-12 13:23:13

对于C++:

##必须产生有效的预处理令牌。

//不被视为预处理令牌。相反,包括//介绍器在内的评论被认为是空白,参见C++17标准的[lex.token]/1 (最终草案)。

如果##不生成有效的预处理令牌(如此处),则程序具有未定义的行为。见[cpp.concat]/3。这意味着编译器甚至不需要用错误消息告诉您您搞砸了。

在执行宏定义和替换等预处理器指令之前,所有注释都会从源文件中删除,因此即使您可以生成//令牌,它也不会被替换,而是语法错误。请参阅[lex.phases]/1.3-1.4

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59704111

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档