文章介绍编译时和运行时的概念,并通过C++和C#的数组越界处理行为加深理解!
编译时
编译时顾名思义就是正在编译的时候。那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码。(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言,比如Java只有JVM识别的字节码,C#中只有CLR能识别的MSIL。另外还有链接器、汇编器。为了了便于理解我们可以统称为编译器)。
编译时就是简单的作一些翻译工作,如检查你有没有粗心写错关键字、词法分析、语法分析.如果发现错误编译器就告诉你.如果用微软的VS的话,点下build,开始编译,如果下面有errors或者warning信息,那都是编译器检查出来的。所谓这时的错误就叫编译时错误,这个过程中做的类型检查就叫编译时类型检查,或静态类型检查(所谓静态就是没把代码加载到内存中运行起来,而只是把代码当文本来扫描)。所以编译时分配内存是错误的说法。
运行时
所谓运行时是指代码被装载到内存中运行的过程(代码保存在磁盘上没装入内存之前是个死家伙,只有跑到内存中才变成活的)。而运行时类型检查与前面讲的编译时类型检查(或者静态类型检查)不一样,并不是简单的扫描代码,而是在内存中进行操作、判断。
代码示例
下面我们来看一下C++和C#中对于数组越界的处理方式,来加深理解编译时和运行时机制。
C++
代码:
int arr[] = {1,2,3};
int result = arr[4];
count << rrsult << end;//<< 是移位运算符,更多请自行谷歌
代码中存在数组越界:
- 当使用编译器编译时,不会报错,因为编译器编译的过程只是代码翻译的过程;
- 当点击Start Debugging,报错了;
- 当点击Start Release,不报错,仍然可以正常运行,得到的值不确定(arr[4]内存越界访问);
C++运行时不做数组越界检查,为了性能问题,C++只做很少且必须的运行时检查操作,如:多态;
所以当使用debugging模式运行时,其实是VS中的某些工具帮助做的数组越界检查,然后报错。
C#
代码:
int arr[] = {1,2,3};
int result = arr[4];
console.WriteLine(result);
代码中存在数组越界:
- 同样的编译可以正常通过;
- 运行后立马报错;
C#与C++不同,它有运行时类型检查机制,可以检查数组越界,但是它并不会返回错误结果描述,而是直接报错,所以需要自行添加异常处理语句捕获出错代码。
关键概念:
- 左值:可以在赋值运算符两边同时使用的值;
- 右值:只能在赋值运算符右边使用的值,不能在左边使用;
int a = 3; int b = a;
a 和 b都是左值,可以在赋值运算符两边使用;
3 是右值,只能在赋值运算符右边使用;
-
#define
定义的对象称为常数,常数的值在编译时就可以确定; -
const
限定词定义并初始化的对象称为常量,常量的值在运行时初始化后才能确定,然后只能作为右值使用;