异常处理

Windows的异常处理 文章目录Windows的异常处理SEHSEH的终结处理SEH的异常处理过滤表达式嵌套使用异常处理和终结处理SEH的实现机制局部展开全局展开VEHSEH和VEH的区别 Windows的异常处理 Windows系统的异常处理有两种: 结构化异常处理(SEH,Structured Exception Handling) 向量化异常处理(VEH,Vectored Exception Handling) SEH Windows定义了SEH机制来规范异常处理代码的设计(对程序员)和编译(对编译器)。 SEH 提供了 阅读详情

C++标准中只规定了异常处理的语法,各编译器厂商也都予以实现。但由于C++标准中并没有规定异常处理的实现过程,造成了不同厂商的编译器,编译后产生的异常处理代码也不相同。本教程中一直使用微软C++编译器系列中的Microsoft Visual C++ 6.0,因此本章也不例外,依然使用VC6.0用于调试讲解。

       C++中异常处理机制由try、throw、catch语句组成。

q        try语句块中负责监视异常。

q        throw用于异常信息的发送,也称之为抛异常。

q        catch用于异常的捕获,做出响应的处理。

 

VC下使用异常处理很方便,只要将以上三个步骤套用即可。但程序的运行过程中出现错误,编译器是如何得知,并找到对应的处理方法?这些对于用于而言全都不得而知,通过本章的分析学习,了解异常处理的实现原理。先从最简单的异常捕获分析。见代码清单1

 

代码清单1     异常处理流程——Debug调试版

// C++源码说明:制造最简单的除0异常

int main(int argc, char* argv[]){

       try{

              throw 0;                                     // 抛出异常

       }

       catch(...){

              printf("异常触发.../r/n");         // 异常除法后执行此处代码

       }

       return 0;

}

// C++源码与对应汇编代码讲解

int main(int argc, char* argv[]){

00401010     push        ebp

00401011     mov        ebp,esp

00401013     push      0FFh

       ; 异常处理函数,__ehhandler$_main函数分析见代码清单2

00401015     push     offset __ehhandler$_main (00413440) 

0040101A   mov      eax,fs:[00000000]        

00401020     push     eax

00401021     mov      dword ptr fs:[0],esp              ; 注册异常回调处理函数

; Debug环境初始化部分略

try{

00401041     mov      dword ptr [ebp-4],0

              throw 1;         // 抛出异常

00401048     mov    dword ptr [ebp-14h],1          ; 设置异常编号

0040104F     push      offset __TI1H (00426628)     ; 压入异常结构

00401054     lea        eax,[ebp-14h]

00401057     push     eax                                     ; 压入异常编号

       ; __CxxThrowException@8 函数讲解见代码清单3

00401058     call      __CxxThrowException@8 (00401790) ; 调用异常分配函数

       }

catch(...){

       printf("异常触发.../r/n");     

0040105D   push      offset string "/xd2/xec/xb3/xa3/xb4/xa5/xb7/xa2.../r/n" (0042501c)

00401062     call       printf (00401200)

00401067     add      esp,4

       }

0040106A   mov      eax,offset __tryend$_main$1 (00401070)

0040106F     ret

return 0;

00401070     mov      dword ptr [ebp-4],0FFFFFFFFh

00401077     xor        eax,eax

}

00401079   mov         ecx,dword ptr [ebp-0Ch]

0040107C   mov         dword ptr fs:[0],ecx

       ; Debug还原环境部分略

00401091     ret

       代码清单1中,首先压入异常回调函数,用于产生异常是,接收并分配到对应的异常处理语句块中。函数__ehhandler$_main便是异常处理的关键实现处,见代码2分析。

 

代码清单2     异常处理函数__ehhandler$_main分析——Debug调试版

=======================示例讲解代码截取自IDA==========================

00413140 __ehhandler$_main proc near             ; DATA XREF: _main+5o

00413140                 mov     eax, offset stru_426468     ; 利用eax传参

00413145                 jmp     ___CxxFrameHandler

00413145 __ehhandler$_main endp

标号stru_426468处信息如下:

00426468      dword_426468     dd   19930520h           ; 编译器生成标识数据

0042646C                      dd   2                                 ; 功能状态标识2

00426470                      dd   offset stru_426640         ; 函数列表首地址

00426474                      dd   1                                 ; try语句块1个

00426478                      dd   offset stru_426670         ; 对应列表首地址

 

___CxxFrameHandler  ,实现如下:

00401210 ; int __cdecl __CxxFrameHandler(void *lp, struct EHRegistrationNode *, int, int)

00401210      var_8      = dword ptr   -8          

00401210      var_4     = dword ptr   -4          

00401210      lp        = dword ptr  8            ; 参数1

00401210      arg_4     = dword ptr  0Ch        ; 参数2

00401210      arg_8      = dword ptr  10h         ; 参数3

00401210       arg_C      = dword ptr  14h         ; 参数4

00401210

00401210       push      ebp

00401211       mov      ebp, esp                        ; 保存栈底,并重新设置栈底

00401213      sub     esp, 8                           ; 申请局部变量空间

00401216      push    ebx

00401217      push    esi

00401218      push    edi                               ; 保存环境

00401219      cld                                             ; 将DF位置0,每次操作后,si、di递增

0040121A      mov       [ebp+var_8], eax           ; var_8局部变量保存stru_426468首地址

0040121D      push    0                      ; 压入参数0作为参数

0040121F     push    0                      ; 压入参数0作为参数

00401221      push    0                      ; 压入参数0作为参数

00401223      mov        eax, [ebp+var_8]

00401226     push    eax                     ; 压入stru_426468结构首地址作为参数

00401227       mov      ecx, [ebp+arg_C]

0040122A     push    ecx                     ; 压入参数4作为参数

0040122B      mov       edx, [ebp+arg_8]

0040122E       push    edx                           ; 压入参数3作为参数

0040122F     mov       eax, [ebp+arg_4]

00401232      push    eax                     ; 压入参数2作为参数

00401233      mov      ecx, [ebp+lp]

00401236     push    ecx                     ; 压入参数1作为参数

00401237     call      ___InternalCxxFrameHandler       ; 调用异常处理函数

0040123C     add            esp, 20h

0040123F      mov      [ebp+var_4], eax

00401242    pop       edi

00401243     pop        esi

00401244     pop       ebx

00401245     mov        eax, [ebp+var_4]

00401248      mov      esp, ebp

0040124A   pop       ebp

0040124B     retn

0040124B ___CxxFrameHandler endp

       代码清单2异常回调函数实现部分,函数__CxxFrameHandler内实际是一个中转工作,并没有真正意义上的完成异常派发。在其中调用了函数___InternalCxxFrameHandler,那么是不是就是由它来完成的异常派发工作呢?先别着急跟踪分析,这个函数传递的参数较多,并且之前使用eax传递的结构体指针也没有搞清楚含义。在不了解敌情的情况下盲目的跟进将会迷失在代码的海洋中。

       那么如何得知这些未知数据呢?依靠IDA强大的分析功能已经有了眉目。首先标号stru_426468被作为函数__InternalCxxFrameHandler的一个参数传递,只需根据IDA查看其声明即可得知结构类型,__InternalCxxFrameHandler函数声明如下:

int __cdecl __InternalCxxFrameHandler(void *lp, struct EHRegistrationNode *, int, int, struct _s_FuncInfo *, int, struct EHRegistrationNode *, int)

       根据代码清单2中的分析,标号地址stru_426468是作为第5个参数被传递,对照以上代码得出其结构类型为_s_FuncInfo。结构说明如下:

struct _s_FuncInfo {

    DWORD MagicNumber;      // 编译器生成标记固定数字0x19930520

    DWORD MaxState;         // 最大的功能状态,栈展开数

    DWORD PUnwindMap;       // 函数列表

    DWORD NTryBlocks;       // try块数量 

    DWORD PTryBlockMap;     // try块列表

};

       PTryBlockMap是一个指向TRY_INFO结构的指针变量,在TRY_INFO结构中描述了try对应的catch块信息,其结构定义如下:

TRY_INFO struc   

StartLevel             dd ?        ; try其实地址

EndLevel              dd ?        ; try终止地址

CatchLevel            dd ?

dwCatchCount       dd ?       ; catch块的个数

pCatch                  dd ?      ; 指向CATCH_INFO类型的指针

field_14                dd ?

TRY_INFO ends

       在CATCH_INFO结构中描述了catch块中的具体信息,如捕捉类型,以及catch块所对应的代码地址等信息。其结构定义如下:

CATCH_INFO struc

Flag dd ?

pTypeInfo dd ?      ; catch块要捕捉的类型

Offset dd ?            ; 用来复制异常对象的栈

CatchProc dd ?       ; catch块的处理代码

CATCH_INFO ends

这里的pTypeInfo异常类型与

由此搞清楚了stru_426468结构中各参数的定义。代码清单1中只是注册了异常处理函数__ehhandler$_main,这个函数由是如何被调用呢?代码清单1中throw编译后,被转换成__CxxThrowException@8,在此函数中通过调用RaiseException来完成异常的派发,最终触发异常处理函数__ehhandler$_main。调试过程中,在异常处理函数__ehhandler$_main设置断点,等待异常触发。当触发断点后,查看stru_426468结构中信息如图1。

图1 标号stru_426468对应结构信息

 

       依照图1中显示,对应结构_s_FuncInfo信息如下:

q        MagicNumber由编译生成的固定数字0x19930520。

q        MaxState最大功能状态为2,表示栈展开数为2。

q        PUnwindMap函数列表首地址0x00426660。

q        try块数为1,对照代码清单1,其中只编写了一个try块。

q        try表地址为0x00426670。

 

有了stru_426468对应的数据,还缺少代码清单2中函数__CxxFrameHandler中4个参数的信息,调试分析看着栈中数据如图2所示。

图2 __CxxFrameHandler参数信息

 

根据图2所示,此时栈顶ESP指向0x0012FAA8,对应内存窗口中查看数据信息如下:

q        地址0x7C9232A8为函数返回地址,此地址为系统使用地址。

q        参数void *lp保存信息为0x0012FB90,对应数据见图3

q        参数struct EHRegistrationNode * 保存信息为0x0012FF74

q        参数3中保存数据0x0012FBB0

q        参数4中保存数据0x0012FF64

图3 lp指向地址数据

 

到此,出现了许多未知数据,那么这些数据它们都有着那些含义,又对应着怎样的结构呢?根据分析它们的使用函数___InternalCxxFrameHandler得知,这个函数才是真正的异常处理函数。见代码清单3

 

代码清单3     __InternalCxxFrameHandler分析——Debug调试版

; 反汇编代码来源自IDA中截取

int __cdecl __InternalCxxFrameHandler(void *lp, struct EHRegistrationNode *, int, int, struct _s_FuncInfo *, int, struct EHRegistrationNode *, int)

       ; 函数内局部变量以及参数标记符定义

00403230      var_8   = dword ptr -8

00403230      var_4   = dword ptr -4

00403230      lp          = dword ptr  8             ; 参数标识符定义void *lp = 0x0012FB90

00403230      arg_4   = dword ptr  0Ch         ; struct EHRegistrationNode * = 0x0012FF74

00403230      arg_8   = dword ptr  10h         ; int = 0x0012FBB0 一个栈地址

00403230      arg_C      = dword ptr  14h         ; int = 0x0012FF64 一个栈地址

00403230      arg_10  = dword ptr  18h         ; struct _s_FuncInfo * 对应标号stru_426468

00403230      arg_14    = dword ptr  1Ch         ; int = 0

00403230      arg_18  = dword ptr  20h         ; struct EHRegistrationNode * = 0

00403230      arg_1C   = dword ptr  24h         ; int = 0

============================函数实现部分==============================

00403230     push      ebp

00403231     mov      ebp, esp

00403233      sub     esp, 8                    ; 申请局部变量栈空间

00403236      mov      eax, [ebp+arg_10]

=============================标志判断处===============================

00403239      cmp      dword ptr [eax], 19930520h  ; 对比标识符

0040323F     jnz     short loc_40324A   ; 对比代码清单2中标识符数据,跳转不成立

00403241      mov     [ebp+var_8], 0      ; 设置局部变量var_8为0

00403248     jmp     short loc_403252   ; 跳转到标号loc_403252处,处理异常

loc_4035CA:

0040324A      call      ?_inconsistency@@YAXXZ ; _inconsistency(void)

0040324F     db         89h

00403250      db         45h

00403251      db           0F8h

loc_403252:                              ; 程序流程执行到此处

00403252      mov       ecx, [ebp+lp]         ; 将lp参数传入ecx中,ecx = 0x0012FB90

=============================标志判断处===============================

00403255       mov       edx, [ecx+4]          ; 参考图3,edx中保存数据为1

       ; 与66h做位于运算,edx中结果为0,像是在做标记检查

00403258      and     edx, 66h               

0040325B     test      edx, edx                ; 检测edx等于0跳转到标号loc_40328E处

0040325D     jz      short loc_40328E  ; 跳转执行成功

0040325F     mov      eax, [ebp+arg_10]

00403262      cmp       dword ptr [eax+4], 0

00403266      jz      short loc_403284

00403268      cmp       [ebp+arg_14], 0

0040326C     jnz     short loc_403284

0040326E     push    0FFFFFFFFh

00403270      mov      ecx, [ebp+arg_10]

00403273      push    ecx

00403274      mov      edx, [ebp+arg_C]

00403277      push    edx

00403278      mov      eax, [ebp+arg_4]

0040327B     push    eax

0040327C     call      ___FrameUnwindToState

00403281     add        esp, 10h

00403284

loc_403284:                                     

00403284     mov      eax, 1

00403289      jmp      loc_40331B           ; 结束异常处理

loc_40328E:                                      ; 程序流程执行到此处                                

=============================标志判断处===============================

0040328E     mov     ecx, [ebp+arg_10] ; 获取参数4到ecx,ecx中保存地址0x0012FBB0

00403291     cmp     dword ptr [ecx+0Ch], 0 ; 比较参数3是否为0,显然不为0

00403295      jz        short loc_403316    ; 此跳转执行失败

=============================标志判断处===============================

00403297      mov    edx, [ebp+lp]         ; 获取lp首4字节数据到edx中,0xE06D7363

0040329A     cmp     dword ptr [edx], 0E06D7363h ; 此处类似标识检查

004032A0     jnz     short loc_4032EE   ; 跳转失败

=============================标志判断处===============================

004032A2     mov       eax, [ebp+lp]         ;传入eax中数据为lp指向地址0x 0012FB90

004032A5   cmp     dword ptr [eax+14h], 19930520h ; 查看图3,获取eax+14h数据

004032AC    jbe     short loc_4032EE  ; 跳转成立,流程执行到标号loc_4032EE处

004032AE   mov      ecx, [ebp+lp]         ; 继续检查工作

004032B1      mov      edx, [ecx+1Ch]

004032B4       mov       eax, [edx+8]

004032B7     mov      [ebp+var_4], eax

004032BA     cmp       [ebp+var_4], 0

004032BE     jz      short loc_4032EE

004032C0   mov      ecx, [ebp+arg_1C]

004032C3     and            ecx, 0FFh

004032C9     push    ecx

004032CA     mov      edx, [ebp+arg_18]

004032CD    push    edx

004032CE     mov      eax, [ebp+arg_14]

004032D1   push    eax

004032D2     mov      ecx, [ebp+arg_10]

004032D5     push    ecx

004032D6      mov      edx, [ebp+arg_C]

004032D9     push    edx

004032DA   mov      eax, [ebp+arg_8]

004032DD     push    eax

004032DE    mov      ecx, [ebp+arg_4]

004032E1     push    ecx

004032E2      mov      edx, [ebp+lp]

004032E5     push    edx

004032E6   call      [ebp+var_4]

004032E9     add            esp, 20h

004032EC   jmp      short loc_40331B

loc_4032EE:                       ; 程序流程执行到此处    

004032EE     mov      eax, [ebp+arg_18]  ; 将参数arg_18中数据传入eax中,eax为0

004032F1     push    eax              ; 压入struct EHRegistrationNode *空指针

004032F2      mov      ecx, [ebp+arg_14]  ; 获取参数arg_14为0值入栈

004032F5     push    ecx           

004032F6     mov      dl, byte ptr [ebp+arg_1C]      ; 获取参数arg_1C为0值入栈

004032F9     push    edx           

004032FA     mov    eax, [ebp+arg_10]  ; 标号stru_426468对应地址入栈

004032FD     push    eax          

004032FE     mov      ecx, [ebp+arg_C]   ; 将地址0x0012FF64入栈

00403301     push    ecx             

00403302      mov      edx, [ebp+arg_8]    ; 将地址0x0012FBB0入栈

00403305     push    edx            

00403306      mov      eax, [ebp+arg_4]    ; 将地址0x0012FF74入栈

00403309     push    eax              ; struct EHRegistrationNode *

0040330A      mov      ecx, [ebp+lp]         ; 获取lp地址到ecx,入栈

0040330D   push    ecx         

       ; 通过此函数找到对应异常处理函数,FindHandler

0040330E     call      ___InternalCxxFrameHandler  

00403313       add            esp, 20h

00403316      mov      eax, 1

loc_40331B:                       ; 函数结尾处

0040331B     mov      esp, ebp

0040331D   pop     ebp

0040331E    retn

0040331E ___InternalCxxFrameHandler endp

       通过分析代码清单3,结合已知数据,在__InternalCxxFrameHandler函数中并没有真正的处理异常,而是进行某些标记的判断,最终有函数FindHandler来完成异常处理。

FindHandler函数说明:(函数原型、实现过程查看frame_ce.cpp)

FindHandler(EHExceptionRecord*,EHRegistrationNode*,_CONTEXT*,void *,_s_FuncInfo const *, uchar, int, EHRegistrationNode *)

       从FindHandler函数的声明中可以得知各传递参数的类型,由此揭开了之前分析过的各个未知参数类型。对应结果如下:

q        参数1对应类型:EHExceptionRecord*,保存数据0x0012FB90

q        参数2对应类型:EHRegistrationNode*,保存数据0x0012FF74

q        参数3对应类型:_CONTEXT*,保存数据0x0012FBB0

q        参数4对应类型:void *,保存数据0x0012FF64

q        参数5对应类型:_s_FuncInfo const *,保存数据0x00426040

q        其余参数均传递0值

 

EHExceptionRecord 结构定义如下:(结构体定义查看winnt.h)

typedef struct _EXCEPTION_RECORD {

    DWORD       ExceptionCode;

    DWORD       ExceptionFlags;

    struct      _EXCEPTION_RECORD *ExceptionRecord;

    PVOID       ExceptionAddress;

    DWORD       NumberParameters;

    ULONG_PTR   ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];

} EXCEPTION_RECORD;

各成员功能说明:(详细解释可查看MSDN帮助文档)

q        ExceptionCode:异常类型,产生异常的错误编号

q        ExceptionFlags:异常标记

q        ExceptionRecord:用于嵌套异常使用

q        ExceptionAddress:异常产生地址

q        NumberParameters:用于指定ExceptionInformation数组中的元素个数

q        ExceptionInformation:存储异常处理的附加参数

   

在这个结构中,重点考察ExceptionCode与ExceptionAddress,它们指定了最重要的异常信息。有了这两项即可得到产生异常的原因,以及异常代码所在地址。对应图3解析异常原因如下:

ExceptionCode:异常类型为0xE06D7363

ExceptionAddress:异常产生地址0x7C812AFB

   

在代码清单3中“cmp      dword ptr [edx], 0E06D7363h”的检测,是在判断是否为C++异常。EHRegistrationNode结构信息如图4所示:

图4 EHRegistrationNode结构信息

 

EHRegistrationNode结构有三个成员,各占四个字节数据。第一项表示每个异常注册节点信息。第二项表示异常注册函数首地址为0x00413440,对比代码清单1中压入栈中的异常注册函数__ehhandler$_main。第三项表示当前异常状态为0表示未处理。

有了这些数据,在FindHandler函数中便会根据提供信息找到try块对应的catch语句块。那么try信息是在合适传入的呢?回顾代码清单1中 throw 1处,压入了两个参数,分别为offset __TI1H (00426628),与异常类型1。

       __TI1H (00426628)是用来说明异常类型的一个结构体。CXX_EXCEPTTION_TYPE,其说明如下:

CXX_EXCEPTTION_TYPE struc

Flag                  dd ?                    

pDestructor       dd ?              ; 用于记录异常对象的析构函数首地址

field_8              dd ?

pTypeInfoTable dd ?              ; 类型列表

CXX_EXCEPTTION_TYPE ends

其中pTypeInfoTable是一个指向CXX_TYPE_INFO_TABLE结构的指针变量,该结构类型定义如下:

CXX_TYPE_INFO_TABLE struc

dwCount               dd ?                            ; CxxTypeInfo数组包含的个数

CxxTypeInfo CXX_TYPE_INFO 3 dup(?) ; 类型信息,可变长度

CXX_TYPE_INFO_TABLE ends

成员dwCount用于说明CxxTypeInfo数组元素个数,CxxTypeInfo是CXX_TYPE_INFO结构类型的变长数组,CXX_TYPE_INFO结构说明如下:

CXX_TYPE_INFO struc

Flag dd ?                    ; 标志

pTypeInfo dd ?             ;  C++的类型信息

dwThisPtrOffset dd ?    ; 基类的this指针偏移

dwVbaseDescr dd ?       ; 虚基类的描述

dwVbaseOffset dd ?      ; 虚基类的this指针偏移

dwSize dd ?                 ; 类的大小

pCopyCtor dd ?            ; 拷贝构造

CXX_TYPE_INFO ends

    根据以上代码分析,总结C++异常处理流程如下:

q        在函数入口处,通过栈方式压入异常处理的回调函数,如代码清单1中__ehhandler$_main。当压入异常处理的回调函数后,栈中结构将发生改变。在函数返回地址与局部变量的中间部分将会插入异常回调函数注册信息。此时try、catch信息已经登记。

q        将throw转换为__CxxThrowException,调用异常回调函数。其中传递了两个参数,第一个记录了throw对象的首地址,或异常类型数值。第二个参数中则记录了异常结构的相关信息。通过调用__CxxThrowException最终执行到异常回调函数中。

q        在异常回调函数中,进行相关检查,根据之前传入数据的记录,一一检查,根据异常类型,调用到对应的catch块中。

q        如果当前异常发生try块中,则取得此try块中的TRY_INFO结构,在TRY_INFO结构中的成员pCatch,该成员指向了CATCH_INFO结构,在此结构中记录了指定 try 块配套出现的所有 catch 块相关信息,包括这个 catch 块所能捕获的异常类型以及起始地址等信息。通过遍历,找到有效的catch块。

q        在异常被抛出、捕获后,将所有生命期已结束的对象正确地析构,将它们所占用的空间正确地回收。

q        跳转到以匹配的 catch 块中,复制当前异常信息到 catch 块,用于异常类型检查。执行catch块中代码。

q        当catch块执行完毕后,析构throw抛出的临时对象。

 

示例中分析的代码并使用类作为异常,而是使用了简单的数字作为异常抛出并捕获,其流程与类大致相同。分析过程相似。

蓝牙2.1+EDR标准协议 Bluetooth SIG发布的蓝牙标准协议,Version 2.1 + EDR 立即下载

相关推荐

Fanuc机器人的坐标变换矩阵的研究2

一、Funuc用户坐标系的介绍 二、用户坐标系与世界坐标系的坐标转换 三、 以用户坐标系1为基础旋转变换后的用户坐标系 四、关于点的WPR的含义 4.1:点在用户坐标系和世界坐标系下的坐标关系 4.2 通过转换矩阵返回去推导WPR

qq_34047402的博客 1522

无法解析的外部符号 __CxxFrameHandler4

编译C++

重剑无锋博客 6877

正负数据如何归一化_生信干货 | LC-MS代谢组学QI软件下机数据代谢物筛选和归一化如何做?...

上海·2019第一届多层组学前言技术发展华东区客户研讨会倒计时1天LC-MS非靶向代谢组学数据下机啦~~拿到一堆数据怎么办?不会高端代码,也不会自己写脚本,我怎么处理数据?​本期小编带来了LC-MS非靶向代谢组学下机数据处理实用干货,包括:下机定性结果表格的解析、代谢物筛选如何做?以及定量数据如何做归一化?实用干货,赶紧来抢~~话不多说,赶紧来学习吧~~非靶向LC-MS代谢组学的分析流程LC-MS...

weixin_36441329的博客 2982

远程桌面 无法定位程序输入点 __CxxFrameHandler4 于动态链接库 C:\windows\system32\spool\DRIVERS\x64\3\FXSUI.DLL 上。

远程桌面 无法定位程序输入点 __CxxFrameHandler4 于动态链接库 C:\windows\system32\spool\DRIVERS\x64\3\FXSUI.DLL 上。

jacke121的专栏 4619

ERA5数据批量下载

ERA5再分析数据的IDM接管下载

qq_38734327的博客 3034

进阶数据结构——链式前向星

链式前向星是一种进阶的数据结构,主要用于图的存储。我希望大家先看这个视频(蓝色字体点进去) 不然你很难理解的。在图论中,图的存储方式主要有邻接矩阵和邻接表两种。邻接矩阵虽然建图简单方便,但占内存较大,节点数量稍微大点的题目就难以使用(适合稠密图);而邻接表虽然节省空间,但其指针形式难写易错,且vector形式的读取速度较慢,易导致大数据下的超时(TLE)。针对上述问题,链式前向星作为一种折中的方式应运而生。链式前向星本质上是一种静态链表,它将数据以链表形式连接在一起。

ycs66的博客 2134

Window10 远程桌面连接提示:“无法定位程序输入点:_CxxFrameHandler4 于动态链接库”错误的解决方法

Window10 远程桌面连接提示:“无法定位程序输入点:_CxxFrameHandler4 于动态链接库”错误的解决方法

Zephyr Hou 的博客 7919

TPL5010硬件看门狗电路

在做一些采集频率很低的产品的时候,会考虑电池供电,比如表、电气表等,为了控制功耗,往往会在设备不需要工作的时候让它进入低功耗模式。为了设备的稳定性,避免死机后无法恢复,必须配置看门狗,一般的看门狗芯片,喂狗间隔时间是几秒钟。这样在喂狗和低功耗之间就产生了一个矛盾,频繁的喂狗就需要频繁的醒过来,这样功耗就很难做到很低。这颗看门狗芯片,特别适合上面的应用。2小时的间隔意味着主控芯片每2小时醒过来喂狗一次即可,而在2.5V供电的情况下,功耗仅仅35nA,几乎可以忽略不计。

zxm8513优快云博客 3306

显示无法定位程序输入点_CxxFrameHandler4于动态链接库,该怎么解决?

尝试在任务管理器中以管理员权限启动cmd,输入以下命令: sfc /scannow 并按下回车尝试修复系统,修复完成后重启再进行确认。 如果用不了sfc命令可以用以下方法 可以尝试在服务中找到Windows Modules Installer,右键启动,或在注册表编辑器中依次展开HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control,在Control右侧找到RegistrySizeLimit,如果没有的话,在右侧空白区右键点击新建—DWORD(32位-值),命

qq_45279131的博客 1万+

ZY1-02D (ZY1E)多光谱数据预处理

资源一号02D卫星(5米光学卫星)于2019年9月12日成功发射,卫星搭载的两台相机,可有效获取115公里幅宽的9谱段多光谱数据以及60公里幅宽的166谱段高光谱数据,其中全色谱段分辨率可达2.5米、 多光谱为10米、高光谱优于30米,高光谱载荷可见近红外和短波红外光谱分辨率分别达到10纳米和20纳米。

热爱分享,热爱记录 4822

【ComfyUI】Flux 完整版文生图

本文介绍了一个基于Flux Dev的AI文生图全流程工作流,通过整合扩散模型、文本编码器和VAE解码器等核心组件,实现从文本到高清图像的端到端生成。工作流包含模型加载、条件构建、潜空间采样、图像解码和成果保存五个关键环节,支持高分辨率图像的细节还原和艺术风格塑造。应用场景涵盖艺术创作、内容生产、教学演示和科研数据准备等领域,适用于对画质和提示遵循性要求严格的场景。文章还提供了相关开发资源和学习教程链接,帮助用户深入理解AI绘图机制和实际应用。

Mr数据杨 1276

libcpmt.lib(ppltasks.obj) : error LNK2001: 无法解析的外部符号 __CxxFrameHandler4问题解决

转自:http://blog.chinaunix.net/uid-24352482-id-3240009.html 这个问题主要是针对libc和libcmt的问题(Runtime library中参数为/MT的条件下需要这两个lib的) 正对VC2005,当你的工程为/MDd时,一般会在linker -> Input -> Ignore specific library中加入LIBCD和LIBCMTD,因为他是使用dll的,而在Release时,如果你选择/MD参数,你也需要加入LIBC和LI

博客标题不能为空 8245

机器学习笔记 - 神经辐射场(NeRF)的简要概述

神经辐射场十分重要。在表示和渲染 3D 场景领域,神经辐射场 (NeRF) 在准确性方面取得了巨大突破。给定底层场景的多个图像,NeRF 可以从任意视点重建该场景的高分辨率、2D 渲染图。与局部光场融合 (LLFF) 和场景表示网络 (SRN) 等现有技术相比,NeRF 更能够捕获场景外观和几何形状的复杂组成部分(例如,依赖于视图的反射和复杂的材料)。NeRF的研究目的是合成同一场景不同视角下的图像。

学以致用 知行合一 1688

Python程序异常处理

异常就是程序运行时发生错误的信号,在程序由于某些原因出现错误的时候,若程序没有处理它,则会抛出异常,程序也的运行也会随之终止;1.程序终止,无法运行下去;2…如果程序是面向客户,那么会使客户的体验感很差,进而影响业务;当处理不确定因素时,比如有用户参与,有外界数据传入时,都容易出现异常;1.由于语法错误导致程序出现异常,这种错误,根本过不了Python解释器的语法检查,必须在程序执行前就改正;

Python编程学习的博客 6456

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

SpringBoot异常处理

把异常页面统一放在templates的error文件夹下404、500实际项目处理中会出现各种各样的异常,如果以上面的方式处理异常,我们就需要写大量的异常处理页面,太过麻烦,可以定义中一个全部异常处理页面使用了全局异常处理后原本的/error页面就会失效共有三种方法:这里举例两种一、注解自定义一个全局异常处理类,只需上面加上 @ControllerAdvice 注解同时要在执行异常处理的方法上标记@ExceptionHandler。

仰望-星空~~的博客 5219

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

spring异常处理

在项目中采用spring的异常处理机制:示例一、在Controller中加@ExceptionHandler注解定义异常拦截的方法,在方法中定义返回的页面: error.jsp 示例二、将异常处理做成一个公共的: 效果:两者区别:示例一只能捕获所属Controller中的方法抛出的异常,不能捕获其他Controller中的,示例二可以捕获所有Controller抛出的异常。下面看源码分析: 由handlerAdapter进行反射调用后,调到controller中的具体方法,抛出的异常最终被捕获,

weixin_38441454的博客 3305

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

什么是异常处理以及异常处理的方式

错误分为两种,一种为语法错误,一种为逻辑错误 异常就是程序运行错误时发出的型号,或者说是程序运行崩溃的结果 常用异常: AttributeError试图访问一个对象没有的属性,比如调用Foo.x,但是Foo下没有x属性 IOError输入/输出异常,基本上是无法打开文件的 ImportError无法引入模块或包,基本上是路径问题或者名称错误 IndentationError语法错误的子类,代码没有...

我一定要成为测试开发! 4918

C# 异常处理

异常处理机制为开发者提供了一种有效的方式,能够将程序的控制权从出现问题的部分合理地转移到其他部分,确保程序在遇到意外情况时依然能够保持相对稳定的运行状态,或者至少能够以一种可控的方式终止并给出相应提示。C# 的异常处理建立在四个至关重要的关键词之上,它们分别是 try、catch、finally 和 throw,各自承担着不同且关键的职责,共同构建起了完善的异常处理体系。除了使用系统预定义的异常类来处理常见的异常情况外,开发者还可以根据实际业务需求定义自己的异常。tryelse。

2401_83367969的博客 2453

C++的异常处理

一、什么是异常处理        一句话:异常处理就是处理程序中的错误。二、为什么需要异常处理,以及异常处理的基本思想        C++之父Bjarne Stroustrup在《The C++ Programming Language》中讲到:一个库的作者可以检测出发生了运行时错误,但一般不知道怎样去处理它们(因为和用户具体的应用有关);另一方面,库的用户知道怎样处理这些错误,但却

大黑暗天 的专栏 2万+

深入浅出Windows异常处理

程序执行过程中难免会发生错误,例如访问非法内存地址或除数为零等,CPU负责检测此类错误并转交给Windows处理,此类错误称为硬件异常。除了硬件异常,操作系统和应用程序还可以显式抛出一个异常,称为软件异常。异常处理是指异常发生后(包括硬件异常和软件异常),Windows或应用程序所执行的一段处理逻辑,这种处理逻辑旨在应对和解决异常情况,从而确保系统或应用程序能够继续运行或安全地终止。 异常发生时,如果程序中没有显式设置相应的异常处理代码,系统通常会启动Windows错误报告(Windows Error Re

huaqiang56的博客 2547

SEH异常处理学习总结

前一段时间,在看异常处理一章内容的时候,发现这一部分还真的挺有尿水:)所以上网搜了一下有关内容,呦嗬,还挺丰富的。当然有些自己还是看不懂,现在就将这些宝贝拿出来跟大家共享一下。首先我们看一下使用异常处理的几种情况:A. 用来处理非致命的错误B. 对API函数的参数合法性的检验(假设参数都是合法的,只有遇到异常的时候进行合法性检验)C. 处理致命错误(退出时最好的选择,但是有的时候可以用异常处理函数

ToBeroOTer的专栏 4589

kotlin中的异常处理_Kotlin异常处理

kotlin中的异常处理In this tutorial, we’ll be discussing Exception Handling in Kotlin. 在本教程中,我们将讨论Kotlin中的异常处理。 什么是例外? (What are Exceptions?) Exceptions are something that can break your program. That make...

从零开始的教程世界 4960

springboot之异常处理

异常分类: 代表编译和系统错误,不允许捕获 标准Java库的方法所激发的异常,包含运行异常Runtime_Exception和非运行异常 Non_RuntimeException 的子类 运行时异常。 非运行时可检测的异常,Java 编译器利用分析方法或构造方法中可能产生的结果来检测程序中是否含有检测异常的处理程序,每个可能的可检测异常、方法或构造方法的 throws 子句必须列出该异常对应的类。 用户自定义异常异常处理用于解决一些程序无法掌控, 但又必须面对的情况。例如,程序需要读取文件、连接网络、使用数

2202_75695913的博客 1251

Java异常处理

/ 支付异常(继承RuntimeException)// 异常附加信息异常处理核心要点理解异常分类:明确Error/Checked/Unchecked的区别选择合适的异常类型:业务异常优先使用RuntimeException保持异常信息完整:包含业务上下文和原始异常全局异常处理:统一REST API错误格式性能优化方向避免在循环内部抛出异常高频调用路径禁用异常控制流使用预检查替代异常捕获:// 优化前try {// 处理越界// 优化后} else {

weixin_44343004的博客 1067
上一篇: 关于sysenter与KiFastSystemCall
下一篇: 异常处理
cmdhack
博客等级 码龄19年 20粉丝 77原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值