为什么编译器错误会分批进行?

时间:2016-07-08 14:50:51

标签: gcc compilation compiler-errors

我注意到编译器错误分批进行。当我做一个make时,我可能会有80个错误或者多个错误。然后,在修复所有这些错误之后,在修复最后一个错误之后,我运行make并且编译器宣布另一批100个错误。这种情况多次发生。编译器似乎经历了几轮或几个阶段,在每个阶段结束时产生一组错误。

请注意,这与人为错误限制无关。 fmax-errors默认为0,这是我编译时的值。

这种行为的解释是什么?

请注意,在这种情况下我使用的是gcc,但我注意到其他编译器正在做同样的事情。

2 个答案:

答案 0 :(得分:1)

你将无法做任何事情。

想想包含多个函数定义的c(++)文件。在错误的函数实现之后,编译器可能根本无法完全解析模块源代码。错误通常会引入歧义,编译器无法解决这些歧义。假设您缺少函数的结束括号。编译器应该如何解释它以进行进一步的错误检查?只是假设括号在那里?或者假设以下函数是第一个函数中的嵌套函数,并且文件末尾实际上缺少结束括号?

在实践中,我很少关心它,因为如果它不构建,那么就不值得推理该程序的行为。你最终必须逐个完成所有的错误。

编译器开发人员对此非常感兴趣。

答案 1 :(得分:0)

通常这是由语法错误引起的(与语义错误相反)。

语法错误可能会混淆编译器。更确切地说,它们可能导致其内部状态与代码应该与之相对应。结果可能是一连串看似无关的错误消息。

使用gcc的一个小例子(类似的考虑可能适用于其他编译器):

#include <stdio.h>
int main(void) 
    char s = "Hello, world";
    puts(s);
}

这有两个错误:缺少{s的类型不正确(需要char*,而不是char)。

一个非常聪明的编译器可能会找出缺少{所需的位置,建议在那时添加它,然后继续编译文件的其余部分(假设它在那里)。没有批评gcc的意图,但它并不那么聪明:

c.c: In function ‘main’:
c.c:3:5: error: parameter ‘s’ is initialized
     char s = "Hello, world";
     ^
c.c:4:5: error: expected declaration specifiers before ‘puts’
     puts(s);
     ^
c.c:5:1: error: expected declaration specifiers before ‘}’ token
 }
 ^
c.c:2:5: error: old-style parameter declarations in prototyped function definition
 int main(void) 
     ^
c.c:5:1: error: expected ‘{’ at end of input
 }
 ^

如果没有{char s;的声明在那时实际上在语法上是有效的,作为旧式(pre-ANSI)参数声明。 gcc(有点合理地)假定它是什么,并抱怨初始化程序 - 但不是关于初始化程序的错误类型。它会将puts调用诊断为不应出现在旧式参数列表中的内容,最后会在文件的最末端抱怨丢失的{

因为它不知道s声明的预期背景,所以它没有正确诊断其他问题。

在我们将{添加到正确的位置后,gcc能够正确诊断剩余的问题:

c.c: In function ‘main’:
c.c:3:14: warning: initialization makes integer from pointer without a cast [enabled by default]
     char s = "Hello, world";
              ^
c.c:4:5: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast [enabled by default]
     puts(s);
     ^
In file included from c.c:1:0:
/usr/include/stdio.h:695:12: note: expected ‘const char *’ but argument is of type ‘char’
 extern int puts (const char *__s);
            ^

在更复杂的情况下,您可能需要多次传递才能获得干净的编译。另一方面,有时编译器能够恢复并继续解析 - 但C的语法使得这种恢复尝试经常失败。

经验法则:如果编译器报告语法错误,修复第一个报告的语法错误并重新编译。如果在第一个语法错误之前存在多个非语法错误,请继续并修复它们。任何遵循语法错误的诊断消息都不可信。 (这不是100%真实;有时这样的消息可能很有用,所以它们恰好指向你可以解决的问题,在重新编译之前继续修复它。)

这需要知道如何识别语法错误消息。一些编译器可能包含单词&#34; syntax&#34;在错误消息中,但你可以看到gcc没有。如果gcc告诉您预期某个特定项目,那就是语法错误消息。

需要注意的另一件事是语法错误消息可能不会指向实际问题,就像在这种情况下一样。您可能需要从报告错误的位置扫描几行(或许多行)以查看导致错误的位置。 C源文件中的一个小错误可以将其转换为仍然具有语法价值的内容,或者几乎有效,但具有非常不同的含义。缺少分号是导致此类问题的常见原因。不匹配的评论分隔符是另一个。

其他工具(例如具有语法突出显示功能的IDE或编辑器)可帮助您在编译之前检测语法错误。