从本质上讲,问题在于无论在什么情况下,错误恢复都很困难。
当您考虑到 C 和 C++ 可怕的语法时,您只会想知道错误消息并没有比这更糟糕!我担心 C 语法是由对语法的基本属性一无所知的人设计的,其中一个是对上下文的依赖越少越好,另一个是你应该努力做到它尽可能明确。
让我们说明一个常见错误:忘记分号。
struct CType {
int a;
char b;
}
foo
bar() { /**/ }
好的,这是错误的,缺少的分号应该去哪里?不幸的是,它是模棱两可的,它可以在之前或之后出现,foo
因为:
- C 认为在定义一个变量之后大步声明一个变量是正常的
struct
- C 认为不为函数指定返回类型是正常的(在这种情况下,它默认为
int
)
如果我们推理,我们可以看到:
- 如果
foo
命名一个类型,那么它属于函数声明
- 如果不是,它可能表示一个变量......当然,除非我们打错字并且它是要写
fool
的,它恰好是一个类型:/
如您所见,错误恢复是非常困难的,因为我们需要推断作者的意思,而语法远不能接受。但这并非不可能,而且大多数错误确实可以或多或少正确地诊断出来,甚至可以从中恢复……只是需要相当大的努力。
似乎从事工作的人gcc
对生成快速代码(我的意思是快速,搜索 gcc 4.6 上的最新基准)和添加有趣的功能(gcc 已经实现了大多数 - 如果不是全部 - 的 C++0x)比生产更感兴趣易于阅读的错误信息。你能怪他们吗?我不能。
幸运的是,有些人认为准确的错误报告和良好的错误恢复是一个非常有价值的目标,其中一些人已经在 CLang 上工作了很长时间,而且他们还在继续这样做。
一些不错的功能,在我的脑海中:
- 简洁但完整的错误消息,其中包括源范围以准确揭示错误的来源
- 当它的意思很明显时,Fix-It会注明
- 在这种情况下,编译器会解析文件的其余部分,就好像修复程序已经存在一样,而不是在乱码行上喷出一行
- (最近)避免包含注释的包含堆栈,以减少内容
- (最近)只尝试公开开发人员实际编写的模板参数类型,并保留 typedefs(因此谈论
std::vector<Name>
而不是std::vector<std::basic_string<char, std::allocator<char>>, std::allocator<std::basic_string<char, std::allocator<char>> >
让一切变得不同)
- (最近)在丢失的情况下正确恢复,以防
template
在另一个模板方法中调用模板方法时丢失
但每一个都需要几个小时到几天的工作。
他们当然不是免费的。
现在,概念应该(通常)让我们的生活更轻松。但它们大多未经测试,因此认为最好将它们从草案中删除。我必须说我为此感到高兴。鉴于 C++ 的相对惯性,最好不要包含尚未彻底修改的功能,而且概念图并没有让我真正兴奋。他们似乎也没有让 Bjarne 或 Herb 激动,因为他们说他们将从头开始重新考虑概念,以制定下一个标准。