为什么嵌套评论被禁止?

时间:2010-06-03 19:41:37

标签: programming-languages comments language-features

为什么嵌套注释在C ++,Java中被禁止,尽管嵌套注释有用,整洁,优雅,可用于注释掉有注释的语句?

7 个答案:

答案 0 :(得分:14)

C和C ++这样做是为了便于解析。这样,当他们点击/ *的评论开始时,解析器可以轻易地扫描到最后。否则,它必须设置并维护一个堆栈,然后如果注释标记不匹配则报告错误。

至于Java为什么这样做,答案很简单 - Java的语法旨在模拟C和C ++。如果允许嵌套注释,它可能会绊倒一些C程序员,并且会编写许多愤怒的博客文章!

答案 1 :(得分:8)

至少对于部分正确的C ++来说,没有问题:

/*
//
//
*/

但是,如果你想在评论中找到一个/ *评论,你可以通过用#if 0包围它来做到这一点,我认为许多编译器会优化掉。如:

#if 0
/*

*/
#endif

答案 2 :(得分:4)

每种语言(家庭)都不同,但一般来说它们不是“禁止”,而是根本不受支持。支持它们是一种设计选择。

选择的一个原因(对于较旧的语言)可能很容易解析。

注意:我记得一个C ++编译器,它可以让它们嵌套。它被标记为“非标准”。

答案 3 :(得分:3)

与C.的一致性/兼容性。

答案 4 :(得分:3)

考虑以下示例:

/* This is a comment /* Nested Comments */ are not allowed. */

/**/之间的任何内容都被视为评论。在上面的示例中,从ThisComments,所有内容都被视为评论,包括/*。 因此,are not allowed. */不在评论中。 这是一个不正确的C语句错误。

考虑这个例子:

// This is an /* valid */ comment

//被视为评论后,该行中的内容是什么。由于/* valid */位于//之后的同一行,因此会将其视为评论的一部分。

答案 5 :(得分:0)

在允许任意长度注释的语言中,程序员偶然注释掉或者在某些极少数情况下“取消注释”或多或少的代码是非常常见的。在许多情况下,这样的错误将导致编译错误,但在其他情况下,它们可能导致代码被破坏。使用现代语法高亮编辑器,每个/*将增加嵌套注释计数器的规则和每个*/将减少它可能不会造成太多麻烦,但没有语法突出显示甚至试图弄清楚什么代码被评论,什么代码不是一个主要问题。

如果一个人从头开始设计一种语言,一个好的方法可能是指定包含可选字符串的注释开始和注释结束标记,并让语言强制要求字符串结束-of-comment标记必须与其对应的注释开始标记中的字符串匹配。假设语法为<|String||String|>,则编译器可以接受<|1| <|2| |2|> |1|>,但拒绝<|1| <|2| |1|> |2|>。即使有人赞成使用#if指令而不是注释,但是附加标记以确保每个结束指令与预期的启动指令匹配的能力将是有用的。

答案 6 :(得分:-1)

问题是你不能简单地跳过&#34;跳过&#34;块。块内部有未知数量的块,因此为了知道该块何时完成,您不能使用常规语言,您必须使用堆栈并遍历每个块,直到堆栈为空,你知道块已经完成了。

你不能跳过块的原因是块的正则表达式只能将/ *与&#34;第一个* /它后来看到&#34;或者&#34;最后的* /它后来看到&#34;或&#34; nth * /之后会看到&#34;。

如果我们选择第一个&#34; * /&#34;我们看到令牌,我们可能有像

这样的代码
/*
    /*

    */
    the compiler matched /* with */ and this line and the next one will confuse it.
*/

如果我们选择最后一个&#34; * /&#34;我们看到令牌,我们有代码,编译器将跳过文件中第一个注释和文件结束的最后一个注释之间的内容。在这种情况下,以下代码将被解析为空字符串。

/*
    /* hello, world! */
*/
int main(int argc, char ** argv) {
    return 0;
}
/* end of file */

我们不能使用跳过n个内部块的第三个选项而不强制所有注释具有确切的深度数,否则它将找不到内部注释并且会混淆。

实际上,有第四种选择明确说明评论可以是单一评论,2范围评论,3范围评论等;但这样做很难看,而且每个级别的深度需要更长的表达式,这种方法将注释限制在特定的深度,这可能适合某些人,而不适合其他人:如果你注释掉已被注释掉的代码怎么办? 3次?

通用解决方案可以使用预处理器实现,例如:

<?php
function stripComments($code) {
    $stack = array();
    $codeOut = '';
    $stringStream = fopen('php://memory', 'r+');
    fwrite($stringStream, $code);  
    rewind($stringStream);  

    while (!feof($stringStream)) {
        $ch = fgetc($stringStream);

        $nextChar = fgetc($stringStream);
        if ($nextChar === false) {
            break;
        }

        if ($ch == '/' && $nextChar == '*') {
            array_push($stack, '/*');          
        } else if ($ch == '*' && $nextChar == '/') {
            if (count($stack) > 0) {
                array_pop($stack);
            } else {
                die('cannot pop from empty stack');
            }
        } else {
            if (count($stack) == 0) {
                $codeOut .= $ch;
                fseek($stringStream, -1, SEEK_CUR);
            }
        }               

        $prevChar = $ch;
    }
    return $codeOut;
};
?>

这比目前使用的C稍微复杂一些:

function stripComments($code) {
    return preg_replace('/\/\*[^\*\/]*\*\//', '', $code);
}

这不会考虑引号内的/**/块,这是一个稍微复杂的堆栈,可以区分&#34; / *&#34;范围和&#34; \&#34;&#34;范围是必需的。

在注释中添加注释的好处是,您可以注释掉包含注释的块而无需手动删除注释,这对于对每行都有注释的块特别令人沮丧。

摘要:可以这样做,但大多数语言都不希望将注释视为自己的范围,因为需要花费更多精力进行解析。