array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 异常与异常处理初步 - 爱码网

在日常程序处理中,很可能发生一些我们意想不到的情况。最典型的情况是,在一次除法或求模运算中,除数是0——这种情况将触发一个典型的除零异常。异常有两个来源,一个来自于CPU,另外一种是来自于程序——我们可以抛出一个异常。

在Delphi中,支持两种处理异常的结构:try...finally...end和try...except...end。许多初学者搞不太清它们的涵义与用法,这里对它们进行一个基本的介绍。

当编译器遇到try时,会生成一些用于处理异常的指令。首先,要确定指定当异常发生后,将应用程序的执行位置转到进行下一步处理的代码,也就是finally段或except段的代码。接下来,将该地址压入用于异常处理的栈结构中,以便正确进出try结构。

先说相对简单一些的except,当异常没发生时,该段中的内容不会得到执行,而是直接退出该异常结构,继续执行end后面的代码。当异常发生时,会根据该段中on...do(如果有的话)来匹配是否属于要处理该异常。如果不处理的话,该段及后面的代码都不会得到执行,而是跳到异常栈中下一个指定的代码位置。如果处理该异常的话,则会执行on...do对应的语句,并且退出异常块,继续执行end后的代码,除非使用raise要求继续由下一个异常处理代码进行处理。未指定on...do的情况,则会被编译器视同对所有的异常进行都处理。

而finally段中的代码,一定会得到执行,不论异常是否发生。当异常没有发生时,执行完finally段后退出该异常,end之后的代码也会得到继续执行。而当异常发生时,首先会执行finally段的代码,然后和except不处理异常的情况一样,跳到异常栈中下一个指定的代码位置继续对异常进行处理。这里需要强调的是,finally段的代码“一定会得到执行”,跟异常是完全无关的——甚至当在try当中使用Exit提前退出该函数时,也会保证在执行finally段中的代码之后,才会退出该函数。

换种形像的方式来说,except会呑掉指定的异常,利用该段中的相应内容对异常进行相应的处理,以使后面的代码能够正确执行。而finally不会呑掉异常,只保证finally段中的内容在任何情况下都会得到正确执行。也许你会产生疑问,为什么finally不呑掉异常呢?因为在实际使用中,即使异常未得到处理,我们仍要保证一些代码能够执行;而如果呑掉直接异常,编译无法判断end后面的内容是否仍然能够正确运行,因而交给下一个异常处理的代码进行处理是更加安全的做法。遗憾的是,Delphi并未支持如C#那样的语法,形成try...except...finally...end的结构,导致许多情况下,仍要进行try结构的嵌套。

正是由于try结构进行了许多对要执行的代码位置的处理,必须小心处理控制流,以保证用于进行异常处理的代码能够匹配执行,因而编译器对控制和跳转语句进行了严格的限制。在try段和except段中,goto的位置必须也处理该段中;而finally段的限制更多,用于跳出该try...finally...end结构的Break、Continue、Exit都不能使用。

正是因为有了这两个结构,Delphi有了强大的语法支持,可以安全完成许多功能。前面提到的finally的典型情况是用于清理try前分配的资源,例如申请了一块内存,为保证不出现内存泄露,把相应的释放代码写在finally段中。当在函数中使用局部变量用于临时分配资源后,使用try...finally...end结构用于执行后续操作和释放是非常好的编程习惯,建议你在阅读本文后将所有这种情况的代码都改成这样。而except用于从异常中恢复,使程序得到正确的执行,例如处理整数运算的溢出(Overflow)。整数类型的数据类型是有固定的宽度的,例如Byte值的范围是0~255,当一个Byte类型的整数进行200+200运算时,运算结果超出了Byte能够容纳的范围,这种情况就是溢出。这种情况下,CPU会在得到运算结果144(400-256)以外,设置标志寄存器的溢出位。遗憾的是,Delphi并没有直接获得该标志位姿态的语法支持,但可以通过另外一种方式检测到:在工程(Project)选项中打开Runtime Errors->Overflow Checking,或在代码中使用编译器开关$Q+或$OVERFLOWCHECKS ON打开溢出异常。当发生整数运算溢出后,RTL会抛出一个溢出异常,这样就可以发现溢出的发生了。假如我们的程序只能对一定范围内的整数进行处理,正常情况下不会出现溢出。但用户也可能输入一个非常大的数字(比如多输了一个0),导致错误的结果。这种情况下,需要检测到溢出,并且提示用户输入的数字过大。这时就可以使用一个try...except...end结构,对溢出异常进行处理,提示用户发生了溢出,原因是输入的数字过大。

这里需要补充一下,计算机对异常的处理是非常复杂的,因而速度也非常慢。例如前面提到的除零异常,它是由CPU触发的,而除法指令(尤其是整数除法指令)本身的处理速度不是一个确定的值,除零运算是其中最慢的情况之一。这里要再补充一些关于CPU与操作系统的知识。以前提到过,x86保护模式支持从ring 0到ring 3一共4个级别的特权模式,数字越低特权级别越高。操作系统工作在级别0中,特权级别最高,一般称为内核态;而我们为一般的应用程序编写的代码,最终工作在级别3中,被称为用户态,只有通过特殊的操作才能进入内核态。如果我没记错的话,只有三种方式由用户态切换到内核态:异常(Exception),中断(Interrupt)和系统调用。其中,异常是我们正在讲的东西;中断是由硬件触发的,例如主板上的其它硬件设备;系统调用是前些年才出现的CPU的特殊指令,Intel使用SYSENTER,AMD使用SYSCALL。当异常产生时,CPU会挂起正在执行的线程,保存相关的寄存器等等,然后切换特权级别,进入内核态将异常交给操作系统用于处理异常的代码进行处理。操作系统会根据异常的情况进行相应的处理,当该异常不属于操作系统要处理的异常时,会将异常的交给要处理异常的应用程序(例如调试器),或者将异常返回给原来的应用程序。因此,上面提到的溢出处理在实际中一般并不使用,而是采用其它的方法进行变通(例如在加法后,运算结果比任何一个加数更小就足以判断了),也就是说这个例子实际上不太恰当(但我一时也想不出更好的例子了)。

而try...finally在一些实际上跟异常无关的应用中也有应用。例如在使用WinAPI要完成一个比较复杂的功能时,要调用多个API,它们都返回一个需要在使用后释放的值,其中任何一个返回非法值时都要提前退出,并且清理前面那些返回值。如果在每一个判断返回值非法的代码中,都手写一堆释放代码再Exit的话,不仅非常累,还很可能多一个或者少一个处理,以后如果要修改代码结构时,工作量也异常巨大。但如果使用了一系列try...finally结构的话,只要一个Exit就可以了,非常方便。

相关文章:

  • 2021-10-09
  • 2021-10-09
  • 2019-02-18
  • 2019-01-21
  • 2019-05-30
  • 2018-04-24
  • 2018-04-12
  • 2018-05-05
猜你喜欢
  • 2021-10-09
  • 2021-11-08
  • 2021-11-08
  • 2018-12-28
  • 2021-10-09
  • 2018-11-01
  • 2018-12-25
相关资源
相似解决方案