运行时和编译时有什么区别?
编译时间和运行时间之间的差异就是头脑敏锐的理论家所说的 phase distinction 的一个例子。这是最难学习的概念之一,尤其是对于没有太多编程语言背景的人来说。为了解决这个问题,我觉得问一下很有帮助
程序满足哪些不变量?在这个阶段会出现什么问题?如果阶段成功,后置条件是什么(我们知道什么)?如果有的话,输入和输出是什么?
编译时间
该程序不需要满足任何不变量。事实上,它根本不需要是一个格式良好的程序。您可以将此 HTML 提供给编译器并观察它... 编译时会出现什么问题: 语法错误 类型检查错误(很少) 编译器崩溃 如果编译器成功,我们知道什么?该程序结构良好——无论使用何种语言,都是一个有意义的程序。可以开始运行程序。 (程序可能会立即失败,但至少我们可以尝试。)输入和输出是什么?输入是正在编译的程序,以及任何头文件、接口、库或其他需要导入以进行编译的巫术。输出希望是汇编代码或可重定位的目标代码,甚至是可执行程序。或者如果出现问题,输出是一堆错误消息。
运行
我们对程序的不变量一无所知——它们是程序员输入的任何内容。运行时不变量很少由编译器单独强制执行。它需要程序员的帮助。可能出错的是运行时错误: 除以零 取消引用空指针 内存不足 程序本身也可能检测到错误: 尝试打开不存在的文件 尝试查找网页和发现所谓的 URL 格式不正确 如果运行时成功,则程序完成(或继续运行)而不会崩溃。输入和输出完全取决于程序员。文件、屏幕上的窗口、网络数据包、发送到打印机的作业,应有尽有。如果程序发射导弹,这是一个输出,它只发生在运行时:-)
我从错误的角度来考虑它,以及何时可以捕获它们。
编译时间:
string my_value = Console.ReadLine();
int i = my_value;
一个字符串值不能被分配一个int类型的变量,所以编译器在编译时就知道这段代码有问题
运行:
string my_value = Console.ReadLine();
int i = int.Parse(my_value);
这里的结果取决于 ReadLine() 返回的字符串。有些值可以解析为 int,有些则不能。这只能在运行时确定
.app
扩展时是编译时间吗?还是每次用户启动应用程序时在启动时发生?
编译时间:作为开发人员,您正在编译代码的时间段。
运行时间:用户运行您的软件的时间段。
你需要更清晰的定义吗?
int x = 3/0
但你不对这个变量做任何事情。我们不打印它或任何东西。这仍然会被视为运行时错误吗?
(编辑:以下适用于 C# 和类似的强类型编程语言。我不确定这是否对您有帮助)。
例如,在您运行程序之前,编译器(在编译时)会检测到以下错误,并会导致编译错误:
int i = "string"; --> error at compile-time
另一方面,编译器无法检测到如下错误。您将在运行时(程序运行时)收到错误/异常。
Hashtable ht = new Hashtable();
ht.Add("key", "string");
// the compiler does not know what is stored in the hashtable
// under the key "key"
int i = (int)ht["key"]; // --> exception at run-time
将源代码翻译成在[屏幕|磁盘|网络]上发生的事情可以(大致)以两种方式发生;称他们为编译和解释。
在已编译的程序中(例如 c 和 fortran):
源代码被输入到另一个程序(通常称为编译器——go figure)中,该程序产生一个可执行程序(或错误)。运行可执行文件(通过双击它,或在命令行上输入它的名称)
第一步发生的事情被称为发生在“编译时”,第二步发生的事情被称为发生在“运行时”。
在解释程序中(例如 MicroSoft basic(在 dos 上)和 python(我认为)):
源代码被输入另一个程序(通常称为解释器),该程序直接“运行”它。在这里,解释器充当您的程序和操作系统(或非常简单的计算机中的硬件)之间的中间层。
在这种情况下,编译时间和运行时间之间的差异更难确定,并且与程序员或用户的相关性更小。
Java 是一种混合,其中代码被编译成字节码,然后在虚拟机上运行,该虚拟机通常是字节码的解释器。
还有一种中间情况,程序被编译为字节码并立即运行(如在 awk 或 perl 中)。
基本上,如果您的编译器可以计算出您的意思或“在编译时”的值是什么,它可以将其硬编码到运行时代码中。显然,如果您的运行时代码每次都必须进行计算,它会运行得更慢,所以如果您可以在编译时确定一些东西,那就更好了。
例如。
恒定折叠:
如果我写:
int i = 2;
i += MY_CONSTANT;
编译器可以在编译时执行此计算,因为它知道 2 是什么,以及 MY_CONSTANT 是什么。因此,它可以避免每次执行都执行计算。
嗯,好吧,运行时是用来描述程序运行时发生的事情。
编译时间用于描述在构建程序时发生的事情(通常是由编译器)。
编译时间:
在编译时完成的事情在结果程序运行时(几乎)不会产生任何成本,但在构建程序时可能会产生很大的成本。
运行:
或多或少正好相反。构建时成本低,运行程序时成本更高。
从另一边;如果某事是在编译时完成的,它只在你的机器上运行,如果某事是运行时的,它就在你的用户机器上运行。
关联
这一点很重要的一个例子是单元携带类型。编译时版本(如 Boost.Units 或 my version in D)最终与使用本机浮点代码解决问题一样快,而运行时版本最终不得不打包有关值所在单位的信息并在每次操作的同时对它们进行检查。另一方面,编译时版本要求值的单位在编译时是已知的,并且无法处理它们来自运行时输入的情况。
作为其他答案的补充,这是我向外行解释的方式:
您的源代码就像一艘船的蓝图。它定义了船的制造方式。
如果您将蓝图交给造船厂,而他们在造船时发现缺陷,他们会在船离开干船坞或接触水之前立即停止建造并向您报告。这是一个编译时错误。这艘船甚至从未真正漂浮或使用过它的引擎。发现错误是因为它甚至阻止了船的制造。
当你的代码编译完成时,就像船正在完成一样。已建成并准备就绪。当你执行你的代码时,这就像在航行中发射船一样。乘客登机,发动机运转,船体在水面上,所以这是运行时间。如果你的船有一个致命的缺陷,导致它在处女航中沉没(或者可能因为额外的头痛而在之后的某次航行),那么它就会遇到运行时错误。
继之前对问题 What is the difference between run-time error and compiler error? 的类似回答之后
编译/编译时间/语法/语义错误:编译或编译时错误是由于输入错误而发生的错误,如果我们不遵循任何编程语言的正确语法和语义,则会引发编译时错误由编译器。在您删除所有语法错误或调试编译时错误之前,它们不会让您的程序执行一行。
示例:在 C 中缺少分号或将 int
错误输入为 Int
。
运行时错误:运行时错误是程序处于运行状态时产生的错误。这些类型的错误会导致您的程序出现意外行为,甚至可能会终止您的程序。它们通常被称为例外。示例:假设您正在读取一个不存在的文件,将导致运行时错误。
在此处阅读有关所有 programming errors 的更多信息
例如:在强类型语言中,可以在编译时或运行时检查类型。在编译时,这意味着如果类型不兼容,编译器会抱怨。在运行时意味着,您可以很好地编译您的程序,但在运行时,它会引发异常。
以下是《Java 编程简介》的作者 Daniel Liang 关于编译的引述:
“用高级语言编写的程序称为源程序或源代码。由于计算机无法执行源程序,因此必须将源程序翻译成机器代码才能执行。翻译可以使用另一种称为解释器或编译器。” (Daniel Liang,“JAVA 编程简介”,第 8 页)。
...他继续...
“编译器将整个源代码翻译成机器代码文件,然后执行机器代码文件”
当我们输入高级/人类可读的代码时,这首先是没有用的!它必须在你的小 CPU 中转化为一系列“电子事件”!第一步是编译。
简单地说:在这个阶段会发生编译时错误,而稍后会发生运行时错误。
记住:程序编译没有错误并不意味着它会运行没有错误。
运行时错误将发生在程序生命周期的就绪、运行或等待部分,而编译时错误将发生在生命周期的“新”阶段之前。
编译时错误示例:
语法错误 - 如果代码不明确,如何将它们编译成机器级指令?您的代码需要 100% 符合语言的语法规则,否则无法编译为有效的 machine code。
运行时错误示例:
内存不足 - 例如,对递归函数的调用可能会导致给定特定程度的变量的堆栈溢出!编译器怎么能预料到这一点!?这不可以。
这就是编译时错误和运行时错误之间的区别
在简单的单词差异 b/w 编译时间和运行时间。
编译时:开发人员以.java格式编写程序并转换为字节码,这是一个类文件,在此编译期间发生的任何错误都可以定义为编译时错误。
运行时:生成的 .class 文件被应用程序用于其附加功能&逻辑结果是错误的并抛出一个错误,这是一个运行时错误
运行时意味着当你运行程序时会发生一些事情。
编译时间意味着当你编译程序时会发生一些事情。
想象一下你是老板,你有一个助理和一个女佣,你给他们一个任务清单,助理(编译时)会抓取这个清单并检查任务是否可以理解,你没有用任何笨拙的语言或语法写作,所以他知道您想为某人分配工作,因此他为您分配了他,并且他了解您想要喝咖啡,因此他的角色结束了女仆(运行时间)开始运行这些任务,所以她去给你煮咖啡,但突然间她找不到要煮的咖啡,所以她停止煮咖啡,或者她采取不同的行动给你泡茶(当程序因为发现错误而采取不同的行动时) )。
编译时间:
在编译时完成的事情在结果程序运行时(几乎)不会产生任何成本,但在构建程序时可能会产生很大的成本。运行:
或多或少正好相反。构建时成本低,运行程序时成本更高。
从另一边;如果某事是在编译时完成的,它只在你的机器上运行,如果某事是运行时的,它就在你的用户机器上运行。
编译时间:将源代码转换为机器代码以使其成为可执行文件所花费的时间称为编译时间。
运行时:当应用程序运行时,称为运行时。
编译时错误是那些语法错误,缺少文件引用错误。运行时错误发生在源代码被编译成可执行程序之后并且程序正在运行时。例如程序崩溃、意外的程序行为或功能不起作用。
我一直认为它与程序处理开销以及它如何影响性能有关,如前所述。一个简单的例子是,要么在代码中定义我的对象所需的绝对内存。
定义的布尔值占用 x 内存,然后在编译的程序中并且不能更改。当程序运行时,它确切地知道要为 x 分配多少内存。
另一方面,如果我只是定义一个通用对象类型(即一种未定义的占位符,或者可能是一个指向某个巨大 blob 的指针),那么我的对象所需的实际内存在程序运行之前是未知的,我给它分配了一些东西,因此必须对其进行评估,然后在运行时动态处理内存分配等(更多的运行时开销)。
然后,如何动态处理将取决于语言、编译器、操作系统、您的代码等。
但是,在那张纸条上,这实际上取决于您使用运行时与编译时的上下文。
这是对“运行时和编译时的区别?”问题的答案的扩展。 -- 与运行时和编译时相关的开销差异?
产品的运行时性能通过更快地交付结果来提高其质量。通过缩短编辑-编译-调试周期,产品的编译时性能有助于其及时性。但是,运行时性能和编译时性能都是实现及时质量的次要因素。因此,只有在整体产品质量和及时性的改进证明合理时,才应该考虑运行时和编译时性能的改进。
进一步阅读的重要来源here:
我们可以将它们分类为静态绑定和动态绑定两大类。它基于使用相应值完成绑定的时间。如果引用是在编译时解析的,那么它是静态绑定,如果引用是在运行时解析的,那么它是动态绑定。静态绑定和动态绑定也称为早期绑定和后期绑定。有时它们也被称为静态多态性和动态多态性。
约瑟夫·库兰代.
运行时和编译时的主要区别是:
如果您的代码中有任何语法错误和类型检查,那么它会抛出编译时错误,其中 - 作为运行时:它在执行代码后进行检查。例如:
int a = 1 int b = a/0;
这里第一行末尾没有分号--->在执行操作b时执行程序后编译时错误,结果是无限--->运行时错误。
编译时不查找代码提供的功能的输出,而运行时查找。
这是一个非常简单的答案:
运行时和编译时是指软件程序开发的不同阶段的编程术语。为了创建程序,开发人员首先编写源代码,它定义了程序将如何运行。小程序可能只包含几百行源代码,而大程序可能包含数十万行源代码。源代码必须编译成机器码才能成为可执行程序。此编译过程称为编译时间。(将编译器视为翻译器)
编译后的程序可以由用户打开和运行。当应用程序运行时,它被称为运行时。
程序员经常使用术语“运行时”和“编译时”来指代不同类型的错误。编译时错误是阻止程序成功编译的语法错误或缺少文件引用等问题。编译器会产生编译时错误,并且通常会指出源代码的哪一行导致了问题。
如果一个程序的源代码已经被编译成可执行程序,它可能仍然存在程序运行时出现的错误。示例包括不起作用的功能、意外的程序行为或程序崩溃。这些类型的问题被称为运行时错误,因为它们发生在运行时。
看看这个例子:
public class Test {
public static void main(String[] args) {
int[] x=new int[-5];//compile time no error
System.out.println(x.length);
}}
以上代码编译成功,没有语法错误,完全有效。但是在运行时,它会引发以下错误。
Exception in thread "main" java.lang.NegativeArraySizeException
at Test.main(Test.java:5)
就像在编译时检查某些情况一样,在运行时检查某些情况后,一旦程序满足所有条件,您将获得输出。否则,您将收到编译时或运行时错误。
您可以通过阅读实际代码来了解代码编译结构。除非您了解所使用的模式,否则运行时结构并不清晰。
public class RuntimeVsCompileTime {
public static void main(String[] args) {
//test(new D()); COMPILETIME ERROR
/**
* Compiler knows that B is not an instance of A
*/
test(new B());
}
/**
* compiler has no hint whether the actual type is A, B or C
* C c = (C)a; will be checked during runtime
* @param a
*/
public static void test(A a) {
C c = (C)a;//RUNTIME ERROR
}
}
class A{
}
class B extends A{
}
class C extends A{
}
class D{
}
对于 SO 来说这不是一个好问题(这不是一个特定的编程问题),但总的来说这不是一个坏问题。
如果您认为这是微不足道的:那么读取时间与编译时间呢,什么时候可以做出有用的区分?编译器在运行时可用的语言呢? Guy Steele(不是傻瓜,他)在 CLTL2 中写了 7 页关于 EVAL-WHEN 的内容,CL 程序员可以使用它来控制它。 2 句话勉强够用一个定义,它本身远没有解释。
一般来说,这是一个语言设计者似乎试图避免的棘手问题。他们经常只是说“这是一个编译器,它做编译时的事情;之后的一切都是运行时的,玩得开心”。 C 被设计为易于实现,而不是最灵活的计算环境。如果您没有在运行时可用的编译器,或者无法轻松控制何时评估表达式,您往往会以语言中的技巧来伪造宏的常见用法,或者用户想出设计模式来模拟拥有更强大的构造。一种易于实现的语言绝对是一个有价值的目标,但这并不意味着它是编程语言设计的终极目标。 (我很少使用 EVAL-WHEN,但我无法想象没有它的生活。)
围绕编译时和运行时的问题空间是巨大的,并且在很大程度上仍未被探索。这并不是说 SO 是进行讨论的正确场所,但我鼓励人们进一步探索这个领域,尤其是那些对它应该是什么没有先入为主的概念的人。这个问题既不简单也不愚蠢,我们至少可以为调查官指出正确的方向。
不幸的是,我不知道有什么好的参考资料。 CLTL2 讲了一点,但是不太适合学习。