int main()
{
i/*nt*/a = 10;
return 0;
}
如果我有上面的代码并且想要计算令牌,那么它是14还是13个令牌?
在变量名内写注释是否有效?你可以假设int i
,int a
,int ia
是全局定义。
int main()
{
i/*nt*/a = 10;
return 0;
}
如果我有上面的代码并且想要计算令牌,那么它是14还是13个令牌?
在变量名内写注释是否有效?你可以假设int i
,int a
,int ia
是全局定义。
Answers:
在程序翻译1的第3阶段中删除了注释:每个注释都替换为一个空格字符。因此,此评论/*nt*/
绝对不是令牌。
如果没有int
,main
,i
,a
或return
定义为预处理的宏,解析程序生成14个令牌(未13):
int
main
(
)
{
i
a
=
10
;
return
0
;
}
除非i
使用typedef
语句将其定义为类型,否则会存在语法错误,因为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
。
像其他任何标记一样,变量名也可以由转义的换行符分隔。转义的换行符是序列,或\
紧随其后的是换行符。在程序翻译的第2阶段,这些序列将从源代码中删除。它们的主要目的是打破多行上的长宏定义。
下面是产生相同的14个令牌的代码片段3:
\
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代码竞赛
\r
以\n
。开头的转义换行符。然而,在某些情况下这会适得其反:注释中可能包含\字符,后跟空格,特别是为了避免行粘贴:const char *path = "C:\\"; // the default path is C:\
The path is "C:\"
似乎比使代码的含义取决于尾随换行符要好。
从词汇的角度来看,注释与空白相同。
C标准中有关词汇元素的6.4p3节规定:
...预处理令牌可以用空格分隔;它由注释(稍后描述)或空格字符(空格,水平制表符,换行符,垂直制表符和换页符)或两者组成。...
更具体地说,评论被翻译成一个空格。这在5.1.1.2p3节中指定:
源文件被分解为预处理令牌和空白字符序列(包括注释)。源文件不得以部分预处理令牌或部分注释结尾。 每个注释都替换为一个空格字符。 换行符将保留。实现定义是保留除换行符以外的每个非空序列的空白字符,还是将其替换为一个空格字符。
为了说明这一点,如果通过预处理器传递代码,则会得到:
int main()
{
i a = 10;
return 0;
}
因此,注释(如空格)可用于分隔标记。
这意味着该代码将包含14个令牌,而不是13个。
只需检查一下代码的形式
int main()
{
int i/*nt*/a = 10;
return 0;
}
将经过预处理。只需在编译器gcc -E myscript.c中添加“ -E”标志,您将得到结果:
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;
}
显然,您可以得出结论,这是一个错误。
cpp -traditional
实施的ANSI前的“传统” C语言中,它将扩展为ia = 10;
。