当前位置: 首页 > news >正文

一次性付费做网站/网站推广的10种方法

一次性付费做网站,网站推广的10种方法,上海网站建设-目前企业网站所面临的困惑,日照网站开发导读: 从本篇文章开始,将全面阐述__try,__except,__finally,__leave异常模型机制,它也即是Windows系列操作系统平台上提供的SEH模型。主人公阿愚将在这里与大家分享SEH( 结构化异常处理)的学习过程和经验总…

导读: 
从本篇文章开始,将全面阐述__try,__except,__finally,__leave异常模型机制,它也即是Windows系列操作系统平台上提供的SEH模型。主人公阿愚将在这里与大家分享SEH( 结构化异常处理)的学习过程和经验总结。 深入理解请参阅<<windows 核心编程>>第23, 24章.

SEH实际包含两个主要功能:结束处理(termination handling)和异常处理(exception handling) 

每当你建立一个try块,它必须跟随一个finally块或一个except块。

一个try 块之后不能既有finally块又有except块。但可以在try - except块中嵌套try - finally块,反过来
也可以。

__try  __finally关键字用来标出结束处理程序两段代码的轮廓

不管保护体(try块)
是如何退出的。不论你在保护体中使用return,还是goto,或者是longjump,结束处理程序
(finally块)都将被调用。

在try使用__leave关键字会引起跳转到try块的结尾

 SEH有两项非常强大的功能。当然,首先是异常处理模型了,因此,这篇文章首先深入阐述SEH提供的异常处理模型。另外,SEH还有一个特别强大的功能,这将在下一篇文章中进行详细介绍。


try-except入门
  SEH的异常处理模型主要由try-except语句来完成,它与标准C++所定义的异常处理模型非常类似,也都是可以定义出受监控的代码模块,以及定义异常处理模块等。还是老办法,看一个例子先,代码如下: 
//seh-test.c

复制代码
void main()
{
// 定义受监控的代码模块
    __try
{
puts("in try");
}
//定义异常处理模块
__except(1)
{
puts("in except");
}
}
复制代码

 呵呵!是不是很简单,而且与C++异常处理模型很相似。当然,为了与C++异常处理模型相区别,VC编译器对关键字做了少许变动。首先是在每个关键字加上两个下划线作为前缀,这样既保持了语义上的一致性,另外也尽最大可能来避免了关键字的有可能造成名字冲突而引起的麻烦等;其次,C++异常处理模型是使用catch关键字来定义异常处理模块,而SEH是采用__except关键字来定义。并且,catch关键字后面往往好像接受一个函数参数一样,可以是各种类型的异常数据对象;但是__except关键字则不同,它后面跟的却是一个表达式(可以是各种类型的表达式,后面会进一步分析)。


try-except进阶
  与C++异常处理模型很相似,在一个函数中,可以有多个try-except语句。它们可以是一个平面的线性结构,也可以是分层的嵌套结构。例程代码如下:

// 例程1
// 平面的线性结构

复制代码
void main()
{
__try
{
puts("in try");
}
__except(1)
{
puts("in except");
}
// 又一个try-except语句
    __try
{
puts("in try1");
}
__except(1)
{
puts("in except1");
}
}
复制代码

// 例程2
// 分层的嵌套结构

复制代码
void main()
{
__try
{
puts("in try");
// 又一个try-except语句
        __try
{
puts("in try1");
}
__except(1)
{
puts("in except1");
}
}
__except(1)
{
puts("in except");
}
}
复制代码

// 例程3
// 分层的嵌套在__except模块中

复制代码
void main()
{
__try
{
puts("in try");
}
__except(1)
{
// 又一个try-except语句
        __try
{
puts("in try1");
}
__except(1)
{
puts("in except1");
}
puts("in except");
}
}
复制代码

 1. 受监控的代码模块被执行(也即__try定义的模块代码);
  2. 如果上面的代码执行过程中,没有出现异常的话,那么控制流将转入到__except子句之后的代码模块中;
  3. 否则,如果出现异常的话,那么控制流将进入到__except后面的表达式中,也即首先计算这个表达式的值,之后再根据这个值,来决定做出相应的处理。这个值有三种情况,如下:
  EXCEPTION_CONTINUE_EXECUTION (–1) 异常被忽略,控制流将在异常出现的点之后,继续恢复运行。
  EXCEPTION_CONTINUE_SEARCH (0) 异常不被识别,也即当前的这个__except模块不是这个异常错误所对应的正确的异常处理模块。系统将继续到上一层的try-except域中继续查找一个恰当的__except模块。
  EXCEPTION_EXECUTE_HANDLER (1) 异常已经被识别,也即当前的这个异常错误,系统已经找到了并能够确认,这个__except模块就是正确的异常处理模块。控制流将进入到__except模块中。
 
try-except深入
  上面的内容中已经对try-except进行了全面的了解,但是有一点还没有阐述到。那就是如何在__except模块中获得异常错误的相关信息,这非常关键,它实际上是进行异常错误处理的前提,也是对异常进行分层分级别处理的前提。可想而知,如果没有这些起码的信息,异常处理如何进行?因此获取异常信息非常的关键。Windows提供了两个API函数,如下:
 

LPEXCEPTION_POINTERS GetExceptionInformation(VOID);
DWORD GetExceptionCode(VOID);

  其中GetExceptionCode()返回错误代码,而GetExceptionInformation()返回更全面的信息,看它函数的声明,返回了一个LPEXCEPTION_POINTERS类型的指针变量。那么EXCEPTION_POINTERS结构如何呢?如下,
 

typedef struct _EXCEPTION_POINTERS { // exp 
PEXCEPTION_RECORD ExceptionRecord; 
PCONTEXT ContextRecord; 
} EXCEPTION_POINTERS;

 

  呵呵!仔细瞅瞅,这是不是和上一篇文章中,用户程序所注册的异常处理的回调函数的两个参数类型一样。是的,的确没错!其中EXCEPTION_RECORD类型,它记录了一些与异常相关的信息;而CONTEXT数据结构体中记录了异常发生时,线程当时的上下文环境,主要包括寄存器的值。因此有了这些信息,__except模块便可以对异常错误进行很好的分类和恢复处理。不过特别需要注意的是,这两个函数只能是在__except后面的括号中的表达式作用域内有效,否则结果可能没有保证(至于为什么,在后面深入分析异常模型的实现时候,再做详细阐述)。看一个例程吧!代码如下:

复制代码
int exception_access_violation_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
printf("存储保护异常\n");
return 1;
}
else 
return 0;
}
int exception_int_divide_by_zero_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
printf("被0除异常\n");
return 1;
}
else 
return 0;
}
void main()
{
__try
{
__try
{
int* p;
// 下面将导致一个异常
p = 0;
*p = 45;
}
// 注意,__except模块捕获一个存储保护异常
        __except(exception_access_violation_filter(GetExceptionInformation()))
{
puts("内层的except块中");
}
//可以在此写除0异常的语句
int b = 0;
int a = 1 / b;
}
// 注意,__except模块捕获一个被0除异常
    __except(exception_int_divide_by_zero_filter(GetExceptionInformation())) 
{
puts("外层的except块中");
}
}
复制代码

上面的程序运行结果如下:

存储保护异常
内层的except块中
Press any key to continue

 

  呵呵!感觉不错,大家可以在上面的程序基础之上改动一下,让它抛出一个被0除异常,看程序的运行结果是不是如预期那样。
  最后还有一点需要阐述,在C++的异常处理模型中,有一个throw关键字,也即在受监控的代码中抛出一个异常,那么在SEH异常处理模型中,是不是也应该有这样一个类似的关键字或函数呢?是的,没错!SEH异常处理模型中,对异常划分为两大类,第一种就是上面一些例程中所见到的,这类异常是系统异常,也被称为硬件异常;还有一类,就是程序中自己抛出异常,被称为软件异常。怎么抛出呢?还是Windows提供了的API函数,它的声明如下:
 

VOID RaiseException(
DWORD dwExceptionCode, // exception code
DWORD dwExceptionFlags, // continuable exception flag
DWORD nNumberOfArguments, // number of arguments in array
CONST DWORD *lpArguments // address of array of arguments
);

 

  很简单吧!实际上,在C++的异常处理模型中的throw关键字,最终也是对RaiseException()函数的调用,也即是说,throw是RaiseException的上层封装的更高级一类的函数,这以后再详细分析它的代码实现。这里还是看一个简单例子吧!代码如下:

复制代码
int seh_filer(int code)
{
switch(code)
{
case EXCEPTION_ACCESS_VIOLATION :
printf("存储保护异常,错误代码:%x\n", code);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT :
printf("数据类型未对齐异常,错误代码:%x\n", code);
break;
case EXCEPTION_BREAKPOINT :
printf("中断异常,错误代码:%x\n", code);
break;
case EXCEPTION_SINGLE_STEP :
printf("单步中断异常,错误代码:%x\n", code);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
printf("数组越界异常,错误代码:%x\n", code);
break;
case EXCEPTION_FLT_DENORMAL_OPERAND :
case EXCEPTION_FLT_DIVIDE_BY_ZERO :
case EXCEPTION_FLT_INEXACT_RESULT :
case EXCEPTION_FLT_INVALID_OPERATION :
case EXCEPTION_FLT_OVERFLOW :
case EXCEPTION_FLT_STACK_CHECK :
case EXCEPTION_FLT_UNDERFLOW :
printf("浮点数计算异常,错误代码:%x\n", code);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO :
printf("被0除异常,错误代码:%x\n", code);
break;
case EXCEPTION_INT_OVERFLOW :
printf("数据溢出异常,错误代码:%x\n", code);
break;
case EXCEPTION_IN_PAGE_ERROR :
printf("页错误异常,错误代码:%x\n", code);
break;
case EXCEPTION_ILLEGAL_INSTRUCTION :
printf("非法指令异常,错误代码:%x\n", code);
break;
case EXCEPTION_STACK_OVERFLOW :
printf("堆栈溢出异常,错误代码:%x\n", code);
break;
case EXCEPTION_INVALID_HANDLE :
printf("无效句病异常,错误代码:%x\n", code);
break;
default :
if(code & (1<<29))
printf("用户自定义的软件异常,错误代码:%x\n", code);
else
printf("其它异常,错误代码:%x\n", code);
break;
}
return 1;
}
void main()
{
__try
{
puts("try块中");
// 注意,主动抛出一个软异常
RaiseException(0xE0000001, 0, 0, 0);
}
__except(seh_filer(GetExceptionCode()))
{
puts("except块中");
}
}
复制代码

上面的程序运行结果如下:
hello
try块中
用户自定义的软件异常,错误代码:e0000001
except块中
world
Press any key to continue

 

上面的程序很简单,这里不做进一步的分析。我们需要重点讨论的是,在__except模块中如何识别不同的异常,以便对异常进行很好的分类处理。毫无疑问,它当然是通过GetExceptionCode()或GetExceptionInformation ()函数来获取当前的异常错误代码,实际也即是DwExceptionCode字段。异常错误代码在winError.h文件中定义,它遵循Windows系统下统一的错误代码的规则。每个DWORD被划分几个字段,如下表所示:
例如我们可以在winbase.h文件中找到EXCEPTION_ACCESS_VIOLATION的值为0 xC0000005,将这个异常代码值拆开,来分析看看它的各个bit位字段的涵义。
C 0 0 0 0 0 0 5 (十六进制)
1100 0000 0000 0000 0000 0000 0000 0101 (二进制)
第3 0位和第3 1位都是1,表示该异常是一个严重的错误,线程可能不能够继续往下运行,必须要及时处理恢复这个异常。第2 9位是0,表示系统中已经定义了异常代码。第2 8位是0,留待后用。第1 6 位至2 7位是0,表示是FACILITY_NULL设备类型,它代表存取异常可发生在系统中任何地方,不是使用特定设备才发生的异常。第0位到第1 5位的值为5,表示异常错误的代码。
  如果程序员在程序代码中,计划抛出一些自定义类型的异常,必须要规划设计好自己的异常类型的划分,按照上面的规则来填充异常代码的各个字段值,如上面示例程序中抛出一个异常代码为0xE0000001软件异常。


总结
  (1) C++异常模型用try-catch语法定义,而SEH异常模型则用try-except语法;
  (2) 与C++异常模型相似,try-except也支持多层的try-except嵌套。
  (3) 与C++异常模型不同的是,try-except模型中,一个try块只能是有一个except块;而C++异常模型中,一个try块可以有多个catch块。
  (4) 与C++异常模型相似,try-except模型中,查找搜索异常模块的规则也是逐级向上进行的。但是稍有区别的是,C++异常模型是按照异常对象的类型来进行匹配查找的;而try-except模型则不同,它通过一个表达式的值来进行判断。如果表达式的值为1(EXCEPTION_EXECUTE_HANDLER),表示找到了异常处理模块;如果值为0(EXCEPTION_CONTINUE_SEARCH),表示继续向上一层的try-except域中继续查找其它可能匹配的异常处理模块;如果值为-1(EXCEPTION_CONTINUE_EXECUTION),表示忽略这个异常,注意这个值一般很少用,因为它很容易导致程序难以预测的结果,例如,死循环,甚至导致程序的崩溃等。
   (5) __except关键字后面跟的表达式,它可以是各种类型的表达式,例如,它可以是一个函数调用,或是一个条件表达式,或是一个逗号表达式,或干脆就是一个整型常量等等。最常用的是一个函数表达式,并且通过利用GetExceptionCode()或GetExceptionInformation ()函数来获取当前的异常错误信息,便于程序员有效控制异常错误的分类处理。
   (6) SEH异常处理模型中,异常被划分为两大类:系统异常和软件异常。其中软件异常通过RaiseException()函数抛出。RaiseException()函数的作用类似于C++异常模型中的throw语句。

C++不常用关键字(__leave)
总结__finally块被执行的流程时,无外乎三种情况。第一种就是顺序执行到__finally块区域内的代码,这种情况很简单,容易理解;第二种就是goto语句或return语句引发的程序控制流离开当前__try块作用域时,系统自动完成对__finally块代码的调用;第三种就是由于在__try块中出现异常时,导致程序控制流离开当前__try块作用域,这种情况下也是由系统自动完成对__finally块的调用。无论是第 2种,还是第3种情况,毫无疑问,它们都会引起很大的系统开销,编译器在编译此类程序代码时,它会为这两种情况准备很多的额外代码。一般第2种情况,被称为“局部展开(LocalUnwinding)”;第3种情况,被称为“全局展开(GlobalUnwinding)”。在后面阐述SEH实现的时候会详细分析到这一点。
第3种情况,也即由于出现异常而导致的“全局展开”,对于程序员而言,这也许是无法避免的,因为你在利用异常处理机制提高程序可靠健壮性的同时,不可避免的会引起性能上其它的一些开销。呵呵!这世界其实也算瞒公平的,有得必有失。

  但是,对于第2种情况,程序员完全可以有效地避免它,避免“局部展开”引起的不必要的额外开销。实际这也是与结构化程序设计思想相一致的,也即一个程序模块应该只有一个入口和一个出口,程序模块内尽量避免使用goto语句等。但是,话虽如此,有时为了提高程序的可读性,程序员在编写代码时,有时可能不得不采用一些与结构化程序设计思想相悖的做法,例如,在一个函数中,可能有多处的return语句。针对这种情况,SEH提供了一种非常有效的折衷方案,那就是__leave关键字所起的作用,它既具有像goto语句和return语句那样类似的作用(由于检测到某个程序运行中的错误,需要马上离开当前的 __try块作用域),但是又避免了“局部展开” 的额外开销。还是看个例子吧!代码如下:
 
复制代码
#include <stdio.h>
void test()
{
puts("hello");
__try
{
int* p;
puts("__try块中");
// 直接跳出当前的__try作用域
__leave;
p = 0;
*p = 25;
}
__finally
{
// 这里会被执行吗?当然
puts("__finally块中");
}
puts("world");
}
void main()
{
__try
{
test();
}
__except(1)
{
puts("__except块中");
}
}
复制代码

上面的程序运行结果如下:
hello
__try块中
__finally块中
world
Press any key to continue

 

http://www.jmfq.cn/news/5281147.html

相关文章:

  • 微网站外链/互联网推广与营销
  • 做去态网站要学java吗/推广有什么好方法
  • 印刷厂网站模板/怎样免费推广自己的网站
  • php学多久可以做网站/企业品牌推广方案
  • 奢侈品b2c电商网站建设/北京网络营销推广外包
  • dw怎么用div css做网站/外贸seo网站
  • 上海门户网站制作/百度收录申请
  • 上海实时新闻/云优化软件
  • 网站建设的基本步骤是哪些/推广下载
  • 漳州做网站建设/seo外包网站
  • 做外贸方面的网站/torrent种子搜索引擎
  • 阿里云建设网站视频/网站搜索引擎优化情况怎么写
  • 南昌微信公众号制作/南山网站seo
  • 淘宝里网站建设公司可以吗/搜索引擎优化策略有哪些
  • 案例剖析网站/关键词优化公司排名榜
  • 帮境外赌场做网站是否有风险/友情链接你会回来感谢我
  • 上海比较好的外包公司/seo费用
  • 辽宁建设工程信息网 招标文件/搜索引擎优化主要包括
  • 项目建设管理 公司 网站/电销外包团队在哪找
  • 雄安专业网站建设公司/全网引擎搜索
  • 柳市建设网站/seo 公司
  • php除了做网站/临沂seo全网营销
  • 深圳流感疫情最新消息今天/手机优化软件哪个好用
  • 六安网站建设招聘/移动营销
  • 投资做任务赚钱的网站/超级外链在线发布
  • 吉林省建设工程信息网站/渠道推广平台
  • 照片做视频的网站/关键词优化排名软件
  • 福州网站开发系列/域名注册要多少钱
  • 做游戏网站公司/如何做线上推广
  • 用dw做淘客网站的步骤/自媒体运营