有意义的诊断消息

时间:2010-08-18 02:59:16

标签: c++ compiler-construction standards diagnostics

看几篇帖子,我觉得很多问题都出现了,因为编译器/实现不会多次发出非常有意义的信息(但并非总是如此)。在模板的情况下尤其如此,其中错误消息可能至少非常令人生畏。一个例子可以discussion topic

因此,我想了解一些事情:

a)为什么编译器有时无法提供更有意义/有用的错误消息?原因纯粹是实用的还是技术性的还是还有其他的东西。 (我没有编译器背景)

b)为什么他们不能引用大多数相关的符合 C ++标准版/节的部分,以便开发人员社区可以更好地学习C ++?

编辑:

另请参阅线程here

编辑:

另请参阅线程here

6 个答案:

答案 0 :(得分:4)

根本问题是编译器诊断处理你没有写的东西。

为了给你一个有意义的错误信息,编译器必须猜测你的意思,然后告诉你你的代码与之不同。

如果你遗漏了分号,编译器显然无法在任何地方看到分号。当然,它可以做的一件事就是猜测“也许用户错过了一个分号。毕竟这是一个常见的错误”。但分号应该在哪里呢?因为您犯了错误,所以代码无法解析为语法树,因此没有明确的指示“树中缺少此节点”。并且可能有多个地方可以插入分号,以便周围的代码可以正确解析。而且,一旦找到可能出现错误的内容,您将尝试解析/重新编译多少代码?编译器可以插入分号,但至少它必须重新启动对该代码块的解析。但也许它在代码中进一步引入了错误。所以也许整个程序应该重新编译,只是为了确保编译器提出的修复实际上是正确的。但这也不是一个选择。这花了太长时间。

假设你有这样的代码:

struct foo {
 ...
}

void bar();

这里的错误是什么?看着它,你和我会说“你在课堂定义后错过了分号”。但是编译器怎么说呢? void可能是一个错字。也许您实际上打算写一个类型为foo的实例的名称。那么真正的错误就是它现在看起来像是一个函数调用。

所以编译器必须猜测。 “看起来它可能是一个类定义,它看起来像是一个类型的名称。如果这是真的,用户就会缺少一个分号来分隔它们。”

猜测不是一门非常精确的科学。问题进一步复杂化,因为每次编译器试图变得聪明并做出猜测时,如果猜测错误,它只会增加混乱。

因此,有时候,输出一条简短而简洁的消息可能会更好,这些消息只说明我们确定的内容(例如,类定义不能跟随类型名称)。这并不像说“你在类定义之后错过了一个分号”那么有用,但如果编译器猜错了,那就不那么有害了。

如果它告诉你错过了分号,而错误实际上是别的,那只会误导你。因此,在最坏的情况下,即使在最好的情况下它不是那么好,也许一个简洁且不太有用的错误消息会更好。

编写好的编译器错误并不容易,特别是在像C ++这样的混乱语言中。 但话虽如此,一些编译器(包括MSVC和GCC)可能会好很多。我相信更好的编译器诊断是Clang的主要目标之一。

答案 1 :(得分:3)

  

人们常犯的错误   试图完全设计一些东西   万无一失是低估了   完全傻瓜的聪明才智。                 --- Douglas Adams

我将尝试解释诊断背后的一些基本原理(正如标准所称):

  

a)为什么编译器有时无法提供更有意义/有用的错误消息?

编译器必须遵守标准。该标准或多或少地定义了编译器需要诊断的所有内容(例如语法错误),因为这些是不变量,供应商需要记录的东西(被称为实现定义为供应商有关于如何记录的一些余地),他们调用的东西未指定(供应商可以在没有记录的情况下离开)然后未定义的行为(如果标准无法定义它,编译器可能会吐出什么错误消息?)。

  

b)为什么他们不能提供最相关的符合C ++标准版/节的参考,以便开发者社区可以更好地学习C ++?

  • 不是每个人都有副本 标准。

  • 相反,编译器尝试的是什么 做的是按类别划分的群组错误 然后修复一个人类可以理解的 足够通用的错误消息 处理各种错误 类别,而仍然存在 有意义的。

  • 此外,并非所有编译器都是标准 兼容。可悲,但确实如此。

  • 有些编译器实现的不止于此 一个标准。你真的期待吗? 他们引用C& V的3个标准 一个简单的“遗失;”的文字 错误?

  • 最后,标准是简洁的 人类可读性低于 委员会想想(好的, 这是一个诙谐的评论但是 反映了事态的美好 准确!)

再次阅读顶部的引用;)

PS:就模板错误消息而言,我必须提供以下内容:

  • 要立即获得救济,请使用STLFilt
  • 祈祷Concepts进入下一个标准

答案 2 :(得分:2)

有些编译器比其他编译器更好。我听说过来自comeau的编译器可以提供更好的错误。您可以在http://www.comeaucomputing.com/tryitout/

上试用

答案 3 :(得分:1)

编辑作者不是因为他们的英语能力而被选中,也不会选择他们的作品来写作。

尽管如此,我认为错误信息在过去十年中持续改善。对于GCC,问题通常是通过过多的信息进行筛选。您链接的讨论是关于“无匹配功能”的消息。这是一个常见错误,通常会出现一系列候选函数。

在这种情况下,参考标准关于过载分辨率的规则甚至可能适得其反。要解决这个问题,我会找到我想要的候选人并将其与呼叫站点进行比较。 99%的时间,我想要一个简单的简单匹配,99%的复杂分辨率机器将不适用。必须审查标准中的解决规则通常表明您正在进入深层斗争。

我认为,无论如何,只有少数程序员真正倾向于或完全能够导航和解释ISO标准。

从好的方面来说,总是可以与任何积极维护的编译器的作者联系。如果你有任何改进措辞的建议,请发送!

答案 4 :(得分:1)

恕我直言,通常重要的不是信息的文本,而是将信息与信息源联系起来的能力。 VS2005中的C ++编译器似乎显示错误消息,指示发生错误的文件,但不显示包含它的文件。这可能是一个真正的痛苦,例如,一个头文件中的错误导致下一个头文件中的编译错误。也可能很难确定预处理器宏发生了什么。

答案 5 :(得分:1)

我读过的其他答案中没有提到的一个因素:C ++编译器的工作原理非常复杂,并且不会通过将他们编译的代码分类为“预期”的东西和“意外”来进一步复杂化。 。例如,作为程序员,我们理解std :: string是std :: basic_string的特定实例,具有各种字符类型,特征,分配器 - 无论如何。所以,当出现错误时我们只想知道它涉及一个字符串,而不是看到所有其他东西。但是,我们要求调试客户端在使用我们的库时遇到的错误消息。我们可能需要确切地看到模板是如何实例化的,以便查看问题所在,并且只是看到代码中的某些typedef - 我们甚至可能无法访问 - 会使错误消息无效。因此,软件堆栈中不同级别的程序员希望看到不同的东西,并且大多数编译器不想购买猜测或允许自定义,他们只是吐出一切并相信程序员将很快学会专注于在他们需要的水平上的东西。大多数时候,程序员很快学会这样做,但有时候比其他人更难。

另一个因素是,有时错误代码可能会有许多小变化都是有效的,因此编译器知道程序员的意图并显示有关该delta的消息是不切实际的。然而,程序员通常不会意识到代码可能几乎有意义的其他方式,并且只是认为编译器因为没有从他们的角度看待它而愚蠢。

干杯, 贝