我在某处阅读了有关编译器和解释器的以下文档: -
编译器搜索程序的所有错误并列出它们。如果程序错误 然后它将程序代码转换为机器代码然后程序就可以了 由单独的命令执行。
解释器按语句检查程序语句的错误。检查后 一个语句,它将该语句转换为机器代码然后执行它 声明。该过程一直持续到最后一个程序声明发生。
我怀疑来自以下代码:
int main()
{
printf("hello")
scanf("%d",&j);
return 0;
}
我正在使用MINGW GCC
编译器。当我编译上面的代码后发生以下事情:
首先我收到错误
error: expected ';' before 'scanf()'
在我纠正上述错误后,我得到第二个错误
error: 'j' undeclared (first use in this function)
所以我想知道为什么两个错误都没有一次列出?
答案 0 :(得分:5)
编译器和解释器在技术上是两个不同的东西,虽然边界有时可能非常流畅。
编译器基本上只是一个语言翻译器。它将源语言作为输入,并生成目标语言作为输出。
解释器使用一种语言(无论是高级还是低级),执行语言描述的代码。
混淆主要是因为大多数现代脚本语言都包含编译器和解释器,其中编译器采用脚本语言并创建一个较低级别的等价物(类似于二进制机器语言),然后解释器就会读取并执行它。 / p>
至于编译器错误的问题,很可能是因为编译器由于第一个错误而无法继续解析scanf
调用,而只是跳过它(包括未声明的变量)。
您还应该知道,在C中,某些错误实际上会导致代码中出现更多错误,例如
int j
printf("Enter something: ");
scanf("%d", &j);
由于在声明变量j
之后缺少分号,您将收到错误,但由于编译器找不到变量scanf
,您也会收到错误{ {1}},即使j
调用是正确的。
另一个在不相关代码中产生后续错误的典型错误示例是忘记头文件中结构的终止分号。如果它是最后一个结构,你甚至可能在头文件中没有任何错误,只是源文件中包含头文件的无关错误。
答案 1 :(得分:3)
您引用的文档有点误导。
编译器和口译员都希望报告尽可能多的错误,但是找不到“程序的所有错误”是不可能的。 (参见暂停问题)
因此,编译器不会“搜索错误”,而是将您的源解析到树表示(AST)中,然后尝试转换该树进入另一种语言的另一个“树”(比如机器代码)。
解释器还会解析您的代码,但转换是在运行时部分完成的。
因此,在您的示例中,缺少的分号会导致解析器失败,因此编译器甚至无法进入编译阶段(报告第二个错误)。
正如其他人所说,编译器和口译员之间的区别不再那么明显了。使用类似的技术,解释器经常编译为机器代码等。
答案 2 :(得分:2)
您引用的编译器定义不是最好的。人们会认为编译器最重要的特性是找到错误。虽然它当然是编译器工作中非常重要的一部分,但主要的是将源代码翻译成其他形式 - 甚至不一定是机器代码。在过去,一些编译器没有列出发现的所有错误 - 至少在一种情况下,整个消息传递是编译器在源中的某处发现错误并停止。即使是现在,有时也无法一次性找到所有错误。
答案 3 :(得分:2)
检测到错误时的常见编译器行为是尝试恢复错误并继续解析以检查其他错误。
当编译器检测到缺少分号错误时,它通常会尝试恢复错误跳过输入直到下一个分号,因此不会解析scanf("%d",&j)
语句并且未检测到缺少j定义错误。
答案 4 :(得分:0)
您引用的文字存在问题。虽然通常是正确的,但通常编译器没有单独的“错误检查”阶段。
它的真正功能是它会立即尝试读取您的代码,如果您的代码中存在错误,则尝试阅读时会失败。
解释器和编译器之间的区别不在于它检查错误时,而是在它实际运行代码时。编译器尝试完全读取程序,然后运行它,解释器读取〜一个语句(甚至只读一个子表达式),然后运行它,读取另一个,运行它。
答案 5 :(得分:0)
编译器和解释器之间的差异如下:
答案 6 :(得分:-1)