4

看了几篇文章,我觉得出现了很多问题,因为编译器/实现没有多次发出非常有意义的消息(但并非总是如此)。在错误消息可能至少非常令人生畏的模板的情况下尤其如此。一个恰当的例子可能讨论主题

因此,我想了解以下几点:

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

b) 为什么他们不能提供相关的符合C++ Standard Verse/section 的参考,以便开发人员社区可以更好地学习 C++?

编辑:

请参阅此处的线程以获取另一个示例。

编辑:

请参阅此处的线程以获取另一个示例。

4

6 回答 6

4

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

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

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

假设你有一些这样的代码:

struct foo {
 ...
}

void bar();

这里有什么错误?看着它,你和我会说“你在类定义之后缺少分号”。但是编译器怎么知道呢?void可能是错字。也许您实际上打算编写 type 实例的名称foo。那么真正的错误将是它后面跟着现在看起来像函数调用的东西。

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

猜测并不是一门非常精确的科学。而且事情变得更加复杂,因为每次编译器试图变得聪明并进行猜测时,如果猜测错误,它只会增加混乱。

因此,有时,最好输出一个简短的消息,只说明我们确定的内容(例如,类定义后面不能跟类型名称)。这不如说“您在类定义后缺少分号”有用,但如果编译器猜错了,危害较小。

如果它告诉您缺少分号,而错误实际上是其他内容,那只会误导您。因此,在最坏的情况下,一个简洁且不太有用的错误消息可能会更好,即使它在最好的情况下并不那么好。

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

于 2010-08-22T19:18:43.973 回答
3

人们在尝试设计完全万无一失的东西时常犯的错误是低估了完全傻瓜的独创性。---道格拉斯·亚当斯

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

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

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

b) 为什么他们不能提供最相关的符合 C++ Standard Verse/section 的参考,以便开发人员社区可以更好地学习 C++?

  • 并非每个人都拥有该标准的副本。

  • 相反,编译器试图做的是按类别对错误进行分组,然后修复一个人类可以理解的错误消息,该错误消息足够通用,可以处理该类别中的各种错误,同时仍然有意义。

  • 此外,并非所有编译器都符合标准。悲伤,但真实。

  • 一些编译器实现了不止一种标准。您真的希望他们引用 3 个标准文本的 C&V 来解决一个简单的“缺失;”错误吗?

  • 最后,该标准比委员会想像的更简洁且可读性差(好吧,这是一个半开玩笑的评论,但相当准确地反映了事态!)

并再次阅读顶部的报价;)

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

  • 如需立即缓解,请使用STLFilt
  • 祈祷概念进入下一个标准
于 2010-08-18T03:14:09.450 回答
2

有些编译器比其他编译器更好。我听说过的comeau 编译器给出了更好的错误。您可以在http://www.comeaucomputing.com/tryitout/上试用一下

于 2010-08-18T03:26:02.493 回答
1

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

也就是说,我认为错误消息在过去十年中一直在改进。使用 GCC,问题通常是筛选过多的信息。您链接的讨论是关于“没有匹配功能”的消息。这是一个常见的错误,通常伴随着大量候选函数。

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

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

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

于 2010-08-18T03:24:34.797 回答
1

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

于 2010-08-18T03:39:44.800 回答
1

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

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

干杯,托尼

于 2010-08-18T06:53:05.487 回答