[笔记]Windows核心编程《二十三》结构化异常处理

简介: [笔记]Windows核心编程《二十三》结构化异常处理

前言

结构化异常处理,SEH(Structured Exception Handling)

SEH的好处:

  • 就是当你编写程序时,只需要关注程序要完成的任务。如果在运行时发生什么错误,系统会发现并将发生的问题通知你。
  • 使用 S E H所造成的负担主要由编译程序来承担,而不是由操作系统承担。当异常块(exception block)出现时,编译程序要生成特殊的代码。编译程序必须产生一些表( t a b l e)来支持处理S E H的数据结构。编译程序还必须提供回调( c a l l b a c k)函数,操作系统可以调用这些函数,保证异常块被处理。编译程序还要负责准备栈结构和其他内部信息,供操作系统使用
    和参考。

SEH 包含两个主要功能:

  • 结束处理
  • 异常处理

SEH和c++异常处理区别:

不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。

一个结束处理程序能够确保去调用和执行一个代码块(结束处理程序,termination handler),

而不管另外一段代码(保护体, guarded body)是如何退出的。结束处理程序的文法结构(使用微软的Visual C++编译程序)如下:

__try
{ //Guard body
...
}
__finally
{ // Terminal Handler
...

__try和__finally关键字用来标出结束处理程序两段代码的轮廓。在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的__finally 代码块能够被执行,不管保护体(try块)是如何退出的。不论你在保护体中使用 return,还是goto,或者是longjump,结束处理程序(finally块)都将被调用。

总之,c++异常处理顺序是:

1.try 2.finally 3. try里的return或者finally之后的代码

C++异常处理的情况

情况1 释放信标情况

代码要等待信标( semaphore),改变保护数据的内容,保存局部变量dwTemp的新值,释放信标,将新值返回给调用程序。

DwORD Funcenstein1( ) {
  DWORD dwTemp;
  //1. Do any processing here.
  __try {
  //2. Request permission to access
  //protected data. and then use it.waitForSing1e0bject(g_hSem,INFINITE);g_dwProtectedData = 5;
  dwTemp = g_dwProtectedData ;
  }
  __fina1ly {
   //3.A1low others to use protected data.Re1easeSemaphore( g_hSem,1,NULL);
  }
  //4. Continue processing.
  return(dwTemp);
}

最后的释放信标放在finally 是一定会执行的。

情况2 释放信标 try中加入return

DwORD dwTemp;
    // 1. Do any processing here.:
  __try {
    // 2. Request permission to access
    // protected data, and then 'use it.
    waitForSing1e0bject(g_hSem,INFINITE);
    g_dwProtectedData = 5;
    dwTemp = g_dwProtectedData ;
    //Return the new value.
    return(dwTemp) ;
  }
  __fina1ly {
    //3.Al1ow others to use protected 
    data.Re1easeSemaphore( g_hSem,1,NULL);
  }
  // Continue processing--this code
  // wi11 never execute in this version.dwTemp = 9;
  return(dwTemp );
}

结果是,返回5。因为当提前return时,finally会先执行,然后再执行try内的return。

当return语句试图退出try块时,编译程序要确保finally块中的代码首先被执行。要保证finally块中的代码在try块中的return语句退出之前执行。Funcens tein2中,将对ReleaseSemaphore的调用放在结束处理程序块中,保证信标总会被释放。这样就不会造成一个线程一直占有信标,否则将意味着所有其他等待信标的线程永远不会被分配CP U时间。

编译程序是如何保证在try块可以退出之前执行finally块的?

查看总结4

情况3 释放信标 在try内使用Goto

DwORD Funcenstein3( ) {
  DwORD dwTemp;
  //1. Do any processing here.
  __try {
    //2. Request permission to access
    //protected data, and then use it.
    WaitForSingle0bject( g_hSem,INFINITE);g_dwProtectedData = 5;
    dwTemp = gdwProtectedData;
    //Try to jump over the fina11y b1ock.
    goto ReturnValue;
  }
  __fina11y {
    //3.Al1ow others to use protected data.
    Re1easeSemaphore( g_hSem,1.NULL);
  }
  dwTemp = 9;
  //4. Continue processing.Returnvalue:
  return(dwTemp);
}

结果是:goto不会执行。会先try到goto时先finally在到retunrn(dwTemp)。

当编译程序看到try块中的goto语句,它首先生成一个局部展开来执行

finally 块中的内容。这一次,在 finally 块中的代码执行之后,在 ReturnValue 标号之后的代码将执行,因为在try块和finally块中都没有返回发生。这里的代码使函数返回 5。而且,由于中断了从try块到finally块的自然流程,可能要蒙受很大的性能损失(取决于运行程序的CPU)。

情况4 释放信标 try调用函数抛异常

try块中的Funcinator函数调用包含一个错误,会引起一个无效内存访问。

DMORD Funcfurter1(){
  DWORD dwTemp;
    //1. Do any processing here.
  __try{
    //2. Request permission to access
    //protected data. and then use it.
    WaitForSing1e0bject( g_hSem,INFINITE);
    dwTemp = Funcinator( g_dwProtectedData) ;
  }
  __final1y {
    //3.A11ow others to use protected data.
    ReleaseSemaphore( g .hSem,1,NULL);
  )
  //4. Continue processing.
  return( dwTemp);
)

结果是,正常释放信标,进程不会提前结束,导致信标没释放。不然就可能引起其他进程等待。

如果结束处理程序足够强,能够捕捉由于无效内存访问而结束的进程,我们就可以相信它也能够捕捉setjump和longjump的结合,还有那些简单语句如break和continue。

情况5 循环中使用try-finally

如下代码执行结果如何?

DWORD FuncaDoodleDoo( ) {
    DWORD dwTemp = 0;
    while (dwTemp < 10){
    __try {
      if ( dwTemp == 2)
        continue;
      if ( dwTemp == 3 )
        break;
    }
       __fina11y {
      dwTemp+t;
       }
     dwTemp++;
  }
  dwTemp += 10;
  return(dwTemp);
}

总结

1.SEH(Structured Exception Handling)和SJLJ(SetJump LongJump)区别对比

SEH:

2.SEH和c++异常处理区别?

SEH和c++异常处理区别:

不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。

3.C++异常处理的特点?

  1. 通过使用结束处理程序,可以避免 return语句的过早执行。
    例如:try内return时 finally可以避免提前返回而没有释放。

注意除了以下几种情况不能处理:

  • 当调用ExitThread或ExitProcess时,将立即结束线程或进程,而不会执行 finally块中的任何代码。
  • 另外,如果由于某个程序调用 TerminalThread或 TerminalProcess,线程或进程将死掉,finally 块中的代码也不执行。
  • 某些 C运行期函数(例如abort)要调用ExitProcess,也使finally块中的代码不能执行。

4. 编译程序是如何保证在try块可以退出之前执行finally块的?

当编译程序检查源代码时,它看到在try块中有return语句。这样,编译程序就生成代码将返回值 保存在一个编译程序建立的临时变量中。编译程序然后再生成代码来执行finally块中包含的指令,这称为局部展开。更特殊的情况是,由于try块中存在过早退出的代码,从而产生局部展开,导致系统执行finall y块中的内容。在finally块中的指令执行之后,编译程序临时变量的值被取出并从函数中返回。

故在编写代码时,就应该避免引起结束处理程序的t r y块中的过早退出,因为程序的性能会受到影响。


相关文章
|
4月前
|
缓存 网络协议 数据安全/隐私保护
[运维笔记] - (命令).Windows server常用网络相关命令总结
[运维笔记] - (命令).Windows server常用网络相关命令总结
192 0
|
6月前
|
消息中间件 C++ Windows
02 MFC - Windows 编程模型
02 MFC - Windows 编程模型
22 0
|
2天前
|
编解码 Linux Windows
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
本文档介绍了在Windows环境下如何为FFmpeg集成libopus和libvpx库。首先,详细阐述了安装libopus的步骤,包括下载源码、配置、编译和安装,并更新环境变量。接着,同样详细说明了libvpx的安装过程,注意需启用--enable-pic选项以避免编译错误。最后,介绍了重新配置并编译FFmpeg以启用这两个库,通过`ffmpeg -version`检查是否成功集成。整个过程参照了《FFmpeg开发实战:从零基础到短视频上线》一书的相关章节。
16 0
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
|
3天前
|
编解码 Linux Windows
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
在Windows环境下,为FFmpeg集成音频编解码库,包括libogg、libvorbis和opencore-amr,涉及下载源码、配置、编译和安装步骤。首先,安装libogg,通过配置、make和make install命令完成,并更新PKG_CONFIG_PATH。接着,安装libvorbis,同样配置、编译和安装,并修改pkgconfig文件。之后,安装opencore-amr。最后,重新配置并编译FFmpeg,启用ogg和amr支持,通过ffmpeg -version检查是否成功。整个过程需确保环境变量设置正确,并根据路径添加相应库。
20 1
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
|
5天前
|
API C++ Windows
windows编程入门_链接错误的配置
windows编程入门_链接错误的配置
10 0
|
25天前
|
Linux 编译器 C语言
FFmpeg开发笔记(二)搭建Windows系统的开发环境
在Windows上学习FFmpeg通常较困难,但通过安装预编译的FFmpeg开发包可以简化流程。首先需要安装MSYS2来模拟Linux环境。下载并执行MSYS2安装包,然后修改msys2_shell.cmd以继承Windows的Path变量。使用pacman安装必要的编译工具。接着,下载预编译的FFmpeg Windows包,解压并配置系统Path。最后,在MSYS2环境中运行`ffmpeg -version`确认安装成功。欲深入学习FFmpeg开发,推荐阅读《FFmpeg开发实战:从零基础到短视频上线》。
32 4
FFmpeg开发笔记(二)搭建Windows系统的开发环境
|
3月前
|
Windows
火山中文编程 -- 第一个windows程序
火山中文编程 -- 第一个windows程序
12 0
|
3月前
|
编译器 API Windows
windows编程基础
windows编程基础
13 0
|
3月前
|
Windows
win32编程 -- windows绘图操作
win32编程 -- windows绘图操作
20 0
|
4月前
|
网络协议 Linux C语言
005.在Windows下编程让效率起飞
windows开发Linux方式: 先用编辑器编写源代码 然后进入Linux 系统,使用gcc编译器(后面会讲),对源代码进行编译运行。 熟练后推荐使用VS2019 开发Linux C++ 程序 将自己的Ip地址设为静态IP
40 1

热门文章

最新文章