运行时和编译时的区别是什么?
当前回答
对于S.O.来说,这不是一个好问题(这不是一个特定的编程问题),但总的来说,这不是一个坏问题。
如果您认为这是微不足道的:那么读时与编译时的区别是什么呢?什么时候这是一个有用的区别?编译器在运行时可用的语言呢?Guy Steele(不是笨蛋,他)在CLTL2中写了7页关于EVAL-WHEN的内容,CL程序员可以使用它来控制这一点。两句话只能勉强给出一个定义,而定义本身还远远不够解释。
In general, it's a tough problem that language designers have seemed to try to avoid. They often just say "here's a compiler, it does compile-time things; everything after that is run-time, have fun". C is designed to be simple to implement, not the most flexible environment for computation. When you don't have the compiler available at runtime, or the ability to easily control when an expression is evaluated, you tend to end up with hacks in the language to fake common uses of macros, or users come up with Design Patterns to simulate having more powerful constructs. A simple-to-implement language can definitely be a worthwhile goal, but that doesn't mean it's the end-all-be-all of programming language design. (I don't use EVAL-WHEN much, but I can't imagine life without it.)
关于编译时和运行时的问题空间是巨大的,而且在很大程度上仍未被探索。这并不是说S.O.是进行讨论的正确场所,但我鼓励人们进一步探索这一领域,特别是那些对它应该是什么没有先入为主概念的人。这个问题既不简单也不愚蠢,我们至少可以给检察官指出正确的方向。
不幸的是,我不知道任何好的参考资料。CLTL2稍微讲了一下,但对于学习它并不是很好。
其他回答
基本上,如果你的编译器能在“编译时”找出你的意思或一个值是什么,它就能硬编码到运行时代码中。显然,如果你的运行时代码每次都要进行计算,那么它会运行得更慢,所以如果你能在编译时确定一些东西,那就更好了。
Eg.
常数合并:
如果我这样写:
int i = 2;
i += MY_CONSTANT;
编译器可以在编译时执行这个计算,因为它知道2是什么,MY_CONSTANT是什么。因此,每次执行时,它都不必执行计算。
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{
}
嗯,好吧,运行时是用来描述程序运行时发生的事情。
编译时间用来描述在构建程序(通常由编译器)时发生的事情。
编译时和运行时之间的差异就是精明的理论家所说的阶段差异的一个例子。它是最难学习的概念之一,特别是对于没有太多编程语言背景的人来说。要解决这个问题,我发现问一下很有帮助
程序满足哪些不变量? 在这个阶段会出现什么问题? 如果阶段成功,后置条件是什么(我们知道什么)? 输入和输出是什么(如果有的话)?
编译时
The program need not satisfy any invariants. In fact, it needn't be a well-formed program at all. You could feed this HTML to the compiler and watch it barf... What can go wrong at compile time: Syntax errors Typechecking errors (Rarely) compiler crashes If the compiler succeeds, what do we know? The program was well formed---a meaningful program in whatever language. It's possible to start running the program. (The program might fail immediately, but at least we can try.) What are the inputs and outputs? Input was the program being compiled, plus any header files, interfaces, libraries, or other voodoo that it needed to import in order to get compiled. Output is hopefully assembly code or relocatable object code or even an executable program. Or if something goes wrong, output is a bunch of error messages.
运行时
We know nothing about the program's invariants---they are whatever the programmer put in. Run-time invariants are rarely enforced by the compiler alone; it needs help from the programmer. What can go wrong are run-time errors: Division by zero Dereferencing a null pointer Running out of memory Also there can be errors that are detected by the program itself: Trying to open a file that isn't there Trying find a web page and discovering that an alleged URL is not well formed If run-time succeeds, the program finishes (or keeps going) without crashing. Inputs and outputs are entirely up to the programmer. Files, windows on the screen, network packets, jobs sent to the printer, you name it. If the program launches missiles, that's an output, and it happens only at run time :-)
下面是《JAVA编程入门》的作者Daniel Liang关于编译的一段话:
用高级语言编写的程序称为源程序或源代码。因为计算机不能执行源程序,所以必须将源程序转换成机器代码才能执行。翻译可以使用另一种被称为解释器或编译器的编程工具来完成。”(Daniel Liang,“JAVA编程入门”,p8)。
...他仍在继续……
编译器将整个源代码翻译成一个机器代码文件,然后执行机器代码文件。
当我们输入高级/人类可读的代码时,这在一开始是无用的!它必须被翻译成一个序列的“电子事件”在你的小CPU!实现这一目标的第一步是编译。
简单地说:编译时错误发生在这个阶段,而运行时错误稍后发生。
请记住:仅仅因为一个程序没有错误地编译,并不意味着它将没有错误地运行。
运行时错误将发生在程序生命周期的准备、运行或等待部分,而编译时错误将发生在生命周期的“新”阶段之前。
编译时错误的例子:
语法错误——如果你的代码有歧义,你怎么能把它们编译成机器级指令??你的代码需要100%符合语言的语法规则,否则它不能被编译成工作的机器代码。
运行时错误的例子:
内存不足——例如,在给定特定程度的变量时,调用递归函数可能会导致堆栈溢出!编译器怎么能预料到这一点!?它不能。
这就是编译时错误和运行时错误的区别