我们可以在变量名中写注释吗?

149
int main()
{
     i/*nt*/a = 10;
     return 0;
}

如果我有以上代码并想要统计标记,那么它会是14个标记还是13个标记?

在变量名中编写注释是否有效?您可以假设int iint aint ia是全局定义的。


14
在早期的ANSI标准之前的“传统”C语言中,至少是由GNU cpp -traditional实现的那样,它会被扩展为ia = 10; - Nate Eldredge
38
多么有趣的问题——为什么以前我从未想到过呢? - WestCoastProjects
180
因为明智的人不会考虑做这样的事情? - jamesqf
5
如果你真的想这样做,可以转而使用Fortran语言。在第一阶段解析时将删除字符串外的空格。 - mpez0
3
我本来要把标题编辑为“…… 变量名中……”,但后来意识到你可能实际上想表达的是“之间”。(我想编辑它是因为对原始标题的答案是“为什么,显然!”重要的部分是“没有空格”)。标题“在C语言中,注释(没有周围空格)是否会分隔标记?”是否能表达你实际的问题? - Peter - Reinstate Monica
显示剩余4条评论
5个回答

204

程序翻译的第三阶段会移除注释1:每个注释将被一个空格字符替换,所以注释/*nt*/绝不是一个记号。

如果没有将intmainiareturn定义为预处理宏,解析程序将产生14个记号(而非13个):

int main ( ) { i a = 10 ; return 0 ; }

除非使用typedef语句将i定义为一种类型,否则存在语法错误,因为i a不符合C语法中的任何规则。

因此,您不能在变量名称内部编写注释,因为注释会将标识符拆分为2个单独的记号。这对于任何预处理和C语言记号2都是正确的。

请注意,您可以在不寻常的位置添加注释,例如在一元运算符和它们的操作数之间或在#和预处理指令及其参数之间:

/**/#/**/include/**/<stdio.h>/**///////////////////////
/**/#/**/define/**/STAT/**/(/**/a/**/)/**/-/**/1/**////
/**/#/**/ifdef/**/STAT/**//////////////////////////////
/**/int/**/main/**/(/**/)/**/{/**//////////////////////
/**/int/**/a/**/=/**/+/**/1/**/;/**////////////////////
/**/printf/**/(/**/"Hello "/**/"world!\n"/**/)/**/;/**/
/**/return/**/STAT/**/;/**/////////////////////////////
/**/}/**///////////////////////////////////////////////
/**/#/**/endif/**//////////////////////////////////////

但上述的宏定义并不是函数式宏,而是普通宏STAT,其扩展为(a) - 1

变量名与其他标记一样可以通过转义换行符进行分割。 转义换行符是由\后紧接着一个换行符组成的序列。 这些序列在程序翻译的第二阶段从源代码中删除。 它们的主要目的是将长宏定义分成多行。

下面是一个代码片段3,它产生相同的14个标记:

\
i\
nt\
 ma\
in()
{\
i/\
*nt\
*/a \
= 10;
r\
et\
urn\
 0;}

请注意,代码着色器错过了被切片和切块的关键字和注释 :)


1) 这种行为在 ANSI-C 即 C89 中有规定。一些古老的编译器可能会产生不同的行为,导致标记粘合,但这些奇特性只具有历史意义。

2) 你可以几乎在字符串常量内部插入注释,利用程序翻译的第6阶段中相邻字符串常量的串联特性: printf("Hello "/* my name is Luca */"world!\n");

3) 这种 圣诞树 的演示风格并不适合用于真实的程序,它说明了如何滥用 C 的输入处理能力。更复杂的技巧赢得了国际模糊 C 代码大赛


66

从词汇角度来看,注释与空格相同。

有关词法元素的第6.4节第3段在C标准中说明:

...... 预处理令牌可以由空格分隔;这包括注释(稍后描述)或空白字符(空格、水平选项卡、换行符、垂直选项卡和换页符),或两者兼而有之。......

更具体地说,注释会被转换为一个空格。这在5.1.1.2节第3段中指定:

源文件被分解为预处理令牌和一系列空白字符序列(包括注释)。源文件不得以部分预处理令牌或部分注释结束。每个注释替换为一个空格字符。保留换行符。除换行符以外的每个非空白空格字符序列是否保留或替换为一个空格字符由实现定义。

举例来说,如果你通过预处理器处理你的代码,你会得到:

  int main()
  {
       i a = 10;
       return 0;

  }

因此,注释(如空格)起到分隔标记的作用。

这意味着代码将包含14个标记,而不是13个。


25

结果将会和你原本写的一样:

i a = 10;

不要:

ia = 10;

12

查看翻译(也称编译)第三阶段,步骤2:"每个注释都会被替换为一个空格字符"

因此,在那一点上,概念上,i/*nt*/a 变成了 i a


评论不适合进行长时间的讨论;此对话已被移至聊天室 - Machavity

1

只是检查你的代码形式

     int main()
    {
        int i/*nt*/a = 10;
        return 0;
    }

预处理后的结果。只需在编译器中添加“-E”标志,gcc -E myscript.c,即可获得以下结果:

e.sharaborin@landau:~$ gcc -E myscript.c
# 1 "myscript.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "myscript.c"
int main()
{
    int i a = 10;
    return 0;
}

显然,您可以得出结论存在错误。

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