嵌套注释
C90只有一种注释风格,就是使用“/*”和“*/”。早在预处理阶段,C预处理器就会剔除所有出现在“/*”和“*/”之间的内容(包括这对记号本身),所以在接下来传送到C编译器的代码文件里是不会出现任何注释内容的。
但这么简单的注释风格有时也会令人头疼。例如,你可能想,什么是注释呢?注释就是写什么东西都无所谓,反正编译器不会看到这些东西。很不幸,C预处理器一般都不支持嵌套注释,如果你这样写:
/*something /* something else */*/
是行不通的。因为预处理器在碰到第一个“*/”时就认为注释已经结束!于是它把到这里为止的注释移除,可想而知,结果留下孤零零一个“*/”—编译程序又报错了。
这样的处理常常令我们很不舒服,例如有时我们调试代码,需要把连续几行代码注释掉观察结果,做法自然是这样写:
语句1;
语句2;
/*
语句3;
*/
语句4;
语句5;
但随着调试的深入,可能我们想连语句2、语句4都注释掉:
语句1;
/*
语句2;
/*
语句3;
*/
语句4;
*/
语句5;
多加一对注释不就解决了?
--中招了。看,你用了嵌套注释。
为了解决这个问题,C++引入另一种风格的注释:使用“//”。预处理器会删除从“//”开始到后面碰到的第一个换行符之间的所有内容。这样就没有嵌套注释的问题了,只不过书写有点繁琐,例如:
语句1;
//语句2;
//语句3;
//语句4;
语句5;
你喜欢注释哪一行都可以,随时可以撤消注释,干脆利落,绝对没有副作用,当然,前提是你一行只写一个语句。
资深程序员一般都更乐意使用C++风格的注释,我也如此建议。不过,你会问,C预处理器可不认识“//”啊?
其实多数C预处理器都“暗中”支持“//”,除非你使用“严格符合C90”之类的编译选项,否则C预处理器是不会阻挠你的。
而且,有个好消息:
C99已经正式采纳C++的注释风格,在今后,你可以光明正大的使用“//”。当然,原来的老风格仍然可以继续使用。
不过,大家最好不要“一只脚踏两只船”,像这样就不好:
// /* 语句1;
语句2;
*/
语句3;
原先用“/*”和“*/”注释掉语句1和语句2,现在不小心又加上“//”,出错了。因为预处理器一看见“//”就不管三七二十一把“///* 语句1;”全部删除掉,结果又留下一个“*/”没有处理。
结束本节之前,再讨论一个有趣的问题。
有些敏感的读者已经坐不住了:那万一我想在字符串里包含“//”之类的注释符怎么办?譬如我要在屏幕上显示这么一行:
we have a // in this line.
能够这样写吗:
printf(“we have a // in this line.\n”);
答案是可以的,只要记住三条原则:
#1 字符串里面的注释符不起注释作用;
#2 注释符里的双引号不起标识字符串的作用;
#3 如果情况混乱则从头找起。
例如:
printf(“we have /* and */ here.”);
则根据原则#1,最后打印出来的字符串不会缺少“/* and */”这部分。
// “This line is a comment.”
由原则#2,可以肯定这一行会被注释掉。
/* “ */ “ */
你可能这样想,第一个“*/”在双引号里面,噢,它不起注释作用,所以这一行被完全注释掉。
不是的。在这么“恶劣”的环境下,我们要找出最先出现的符号是注释符还是双引号,在这个例子里,注释符最先带头,所以根据原则#2,双引号不起任何作用,当预处理器碰到第一个“*/”时就认为注释结束,预处理的结果是上面这一行语句最后剩下:
“ */
另:
其实C/C++程序员可以使用预处理指令实现嵌套注释:
语句1;
#if 0
语句2;
#if 0
语句3;
#endif
语句4;
#endif
语句5;
因为预处理器在分析预处理指令时不仅进行词法分析,还进行语法分析,这就比使用“/*”和“*/”高级,后者仅仅涉及词法分析。
两个小例子:
例一:
/*/**/"*/"/*"/**/
在不允许嵌套注释的编译器中相当于 "*/"
不允许嵌套的从前往后寻找配对 找到即开始注释
故/*/**/"*/"/*"/**/ -> "*/"/*"/**/ -> "*/"
在允许嵌套注释的编译器中相当于 "/*"
允许嵌套的找到最后一个左边符号 然后开始寻找配对 找到即开始注释
故/*/**/"*/"/*"/**/ -> /*"*/"/*"/**/ -> "/*"/**/ -> "/*"
例二:
/*/*/0*/**/1
在不允许嵌套注释的编译器中相当于 0*1
在允许嵌套注释的编译器中相当于 1
来源:《C 陷阱与缺陷》
阅读(4696) | 评论(0) | 转发(0) |