Windows 异常处理原理

59、Windows SEH 异常处理机制详解 本文详细解析了 Windows 系统中的结构化异常处理机制(SEH),包括其基本原理、不同版本(SEH3、SEH4)的实现方式以及在 x64 架构下的优化处理。通过代码示例和汇编分析,深入探讨了异常处理链的工作流程、作用域表结构、安全保护机制以及在实际开发中的应用技巧。文章还对比了不同版本之间的差异,帮助开发人员在实际项目中选择合适的异常处理策略,提升程序的健壮性和安全性。 阅读详情

Windows运行过程中,不可避免会产生各种异常(由内核或应用程序),系统提供了一套强大的异常处理机制,灵活的使用它,可以让我们的应用程序变的更健壮。

了解涉及异常处理的数据结构

IDT 系统中断表

有异常产生时,处理器根据IDT的中断号,找到对应的处理函数 KiTrapxx,异常处理函数会将异常封装到一个数据结构。

typedef struct _EXCEPTION_RECORD32 {
	DWORD    ExceptionCode; //异常代码
	DWORD ExceptionFlags;  //异常标志
	DWORD ExceptionRecord;  //EXCEPTION_RECORD32指针
	DWORD ExceptionAddress; //产生异常时的地址
	DWORD NumberParameters; //异常附加信息数量
	DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //异常附加信息,指针指向一个数组
} EXCEPTION_RECORD32, *PEXCEPTION_RECORD32;

CONTEXT异常上下文 ,不太严谨,姑且这样认为吧,它包含了异常产生时,执行环境的详细信息

typedef struct _CONTEXT {

	//标识哪些成员是有效的
	DWORD ContextFlags;


	//调试寄存器 
	DWORD   Dr0;
	DWORD   Dr1;
	DWORD   Dr2;
	DWORD   Dr3;
	DWORD   Dr6;
	DWORD   Dr7;


	FLOATING_SAVE_AREA FloatSave;

	//
	// This section is specified/returned if the
	// ContextFlags word contians the flag CONTEXT_SEGMENTS.
	//

	DWORD   SegGs;
	DWORD   SegFs;
	DWORD   SegEs;
	DWORD   SegDs;

	//
	// This section is specified/returned if the
	// ContextFlags word contians the flag CONTEXT_INTEGER.
	//

	DWORD   Edi;
	DWORD   Esi;
	DWORD   Ebx;
	DWORD   Edx;
	DWORD   Ecx;
	DWORD   Eax;

	//
	// This section is specified/returned if the
	// ContextFlags word contians the flag CONTEXT_CONTROL.
	//

	DWORD   Ebp;
	DWORD   Eip;
	DWORD   SegCs;              // MUST BE SANITIZED
	DWORD   EFlags;             // MUST BE SANITIZED
	DWORD   Esp;
	DWORD   SegSs;

	//
	// This section is specified/returned if the ContextFlags word
	// contains the flag CONTEXT_EXTENDED_REGISTERS.
	// The format and contexts are processor specific
	//

	BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

当KiTrapxxx处理完成并将异常信息封装好后,转而调用系统内核nt!KiDispatchException函数。

KiDispatchException 该函数是异常处理的核心函数,该函数代码比较长,这里贴出函数头的部分代码。

该函数会根据异常类型及是否存在调试器,来进行不同的处理。

  • 内核态

    1.如果存在内核调试器,并设置处理进度为第一次处理,内核调试器如果不能处理异常则会中断,重新把控制权交给用户,如果调试器处理了异常,那么会从发生异常的地方继续执行指令。

    2.不存在内核调试器,或者内核调试器不能处理异常,内核就会调用RtlDispatchException函数,依次调用注册的异常处理函数。(SEH)

    3.如果RtlDispatchException也没有能够处理异常,内核会重新将异常交给调试器。

    4.如果调试器仍然处理不了,此时就可以见到久违的蓝屏错误了。(0x0000008e)

 

  • 用户态

1.如果存在内核调试器,将异常交给调试器处理。

2.如果存在用户态调试器,则交给调试器处理,调试器未处理该异常或者不存在调试器,KiDispatchException会压入2个数据结构,exception_record、context,让后将控制权返回给用户态函数,位于ntdll!RtlDispatchException。

3.如果RtlDispatchException未能处理异常,此时会再次将异常返回给内核KiDispatchException,它会将异常重新转给用户态调试器,如果仍然无法处理异常,就结束进程。

4.结束进程前,系统会再次调用注册的异常处理函数,然后会结束异常进程。

 

SEH (结构化异常处理)

前面讲到的是内核异常处理流程,下面说下用户态的异常处理。

SEH是一种异常处理机制,发生异常时,系统通过它找到处理函数,处理该异常。

涉及到的数据结构

TEB  线程环境块(翻译过来是这样的)

typedef struct _TEB {
    PVOID Reserved1[12];
    PPEB ProcessEnvironmentBlock;
    PVOID Reserved2[399];
    BYTE Reserved3[1952];
    PVOID TlsSlots[64];
    BYTE Reserved4[8];
    PVOID Reserved5[26];
    PVOID ReservedForOle;  // Windows 2000 only
    PVOID Reserved6[4];
    PVOID TlsExpansionSlots;
} TEB, *PTEB;

TIB 线程信息块

typedef struct _NT_TIB32 {
    DWORD ExceptionList;
    DWORD StackBase;
    DWORD StackLimit;
    DWORD SubSystemTib;

#if defined(_MSC_EXTENSIONS)
    union {
        DWORD FiberData;
        DWORD Version;
    };
#else
    DWORD FiberData;
#endif

    DWORD ArbitraryUserPointer;
    DWORD Self;
} NT_TIB32, *PNT_TIB32;

异常处理结构( ExceptionList成员)

typedef struct _EXCEPTION_REGISTRATION_RECORD {
    struct _EXCEPTION_REGISTRATION_RECORD *Next; //下一个处理
    PEXCEPTION_ROUTINE Handler; //异常处理函数
} EXCEPTION_REGISTRATION_RECORD;

异常处理函数声明

typedef
_IRQL_requires_same_
_Function_class_(EXCEPTION_ROUTINE)
EXCEPTION_DISPOSITION
NTAPI
EXCEPTION_ROUTINE (
    _Inout_ struct _EXCEPTION_RECORD *ExceptionRecord, //异常信息
    _In_ PVOID EstablisherFrame, //陷阱帧
    _Inout_ struct _CONTEXT *ContextRecord, //异常上下文
    _In_ PVOID DispatcherContext // 未知
    );

typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE;

从XP到现在的win10,这些数据结构都没有大的变动。

从以上流程知道,要处理异常,需要注册SEH处理函数,SEH位于TIB头,是一个单项链表,通过next指向下一个处理函数。

SEH异常处理代码(此处代码来自网上,做了部分调整)

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <winternl.h>


//异常处理函数
DWORD dwTest;
EXCEPTION_DISPOSITION NTAPI ExceptHandler(
	_Inout_ struct _EXCEPTION_RECORD *ExceptionRecord,
	_In_ PVOID EstablisherFrame,
	_Inout_ struct _CONTEXT *ContextRecord,
	_In_ PVOID DispatcherContext) {
	printf("进入异常处理\n");
	printf("异常地址:%X<异常代码:%X>\n", ExceptionRecord->ExceptionAddress,
		ExceptionRecord->ExceptionCode);
	ContextRecord->Eax = (DWORD)(&dwTest);
	return ExceptionContinueExecution;
}



int main()
{
	PTEB teb=NULL;

	_asm
	{
		mov eax,fs:[0]
		mov teb,eax
	}

	printf("TEB %X \n", teb);


	printf("注册SEH\n");
	__asm {
		lea eax, ExceptHandler  //将异常处理函数地址装入eax
		push eax //异常处理函数入栈
		push fs : [0] //构造EXCEPTION_REGISTRATION_RECORD
		mov dword ptr fs : [0], esp //将构造好的处理函数加入SEH链表头部
	}

	__asm {
		xor eax, eax
		mov dword ptr[eax], 1234h  //内存访问无效异常
	}
	printf("删除SEH\n");

	//卸载异常处理函数并恢复堆栈
	__asm {
		pop dword ptr fs : [0]
		add esp, 4
	}

	printf("dwTest=%X\n", dwTest);

	system("pause");
}

下面在调试器中看下系统的异常处理流程,首先在内核的KiDispatchException函数下断,运行exe。

bp 0x83ef7dc1虚拟机有问题,触发异常后关闭,就在用户模式下调试了。

注册SEH前的异常处理列表

0:000> dd fs:[0]
0053:00000000  0019ff60 001a0000 0019d000 00000000
0053:00000010  00001e00 00000000 00260000 00000000
0053:00000020  00004d5c 00000308 00000000 0026002c
0053:00000030  0025d000 00000000 00000000 00000000
0053:00000040  00000000 00000000 00000000 00000000
0053:00000050  00000000 00000000 00000000 00000000
0053:00000060  00000000 00000000 00000000 00000000
0053:00000070  00000000 00000000 00000000 00000000

0x19ff60 ExceptionList地址,继续查看 dd 0x19ff60

0:000> dd 0x19ff60
0019ff60  0019ffcc 00434bb0 af181fd2 00000000
0019ff70  0019ff80 74b50419 0025d000 74b50400
0019ff80  0019ffdc 7750662d 0025d000 6bd86c90
0019ff90  00000000 00000000 0025d000 00000000
0019ffa0  00000000 00000000 00000000 00000000
0019ffb0  00000000 00000000 00000000 00000000
0019ffc0  00000000 0019ff8c 00000000 0019ffe4
0019ffd0  775186d0 1c9b01fc 00000000 0019ffec

19ffcc 指向下一个异常处理函数,434bb0地址为当前异常处理函数地址。

我们看下,下一个异常处理函数

0:000> dd 0x19ffcc
0019ffcc  0019ffe4 775186d0 1c9b01fc 00000000
0019ffdc  0019ffec 775065fd ffffffff 775251d2
0019ffec  00000000 00000000 0042c6e5 0025d000
0019fffc  00000000 78746341 00000020 00000001
001a000c  00003318 000000dc 00000000 00000020
001a001c  00000000 00000014 00000001 00000007
001a002c  00000034 0000017c 00000001 00000000
001a003c  00000000 00000000 00000000 00000000

0x775186d0处函数 ,这是MSVC编译器对系统SEH异常的增强,后面会陆续讲到。

 

接着安装我们的SEH异常处理函数。

004325e6 8d05cfc34200   lea     eax, [targetexe!ILT+970(?ExceptHandlerYG?AW4_EXCEPTION_DISPOSITIONPAU_EXCEPTION_RECORDPAXPAU_CONTEXT (0042c3cf)]
004325ec 50             push    eax
004325ed 64ff3500000000 push    dword ptr fs:[0]
004325f4 64892500000000 mov     dword ptr fs:[0], esp fs:0053:00000000=0019ff60  //安装异常处理函数
004325fb 33c0           xor     eax, eax
004325fd c70034120000   mov     dword ptr [eax], 1234h //产生内存写入异常

查看安装SEH后的异常处理列表

0:000> dd 19fe44
0019fe44  0019ff60 0042c3cf 00646110 00499d2c
0019fe54  0025d000 cccccccc cccccccc cccccccc
0019fe64  cccccccc cccccccc cccccccc cccccccc
0019fe74  cccccccc cccccccc cccccccc cccccccc
0019fe84  cccccccc cccccccc cccccccc cccccccc
0019fe94  cccccccc cccccccc cccccccc cccccccc
0019fea4  cccccccc cccccccc cccccccc cccccccc
0019feb4  cccccccc cccccccc cccccccc cccccccc

0x42c3cf 这里是我们注册的SEH处理函数地址。

内核会将异常转到用户态,然后调用我们注册的处理函数,这就是windows异常处理的整体流程,后面会陆续分享涉及SEH、VEH等处理细节。

C++异常处理与Windows SEH机制实战演示 在C++编程语言中,异常处理是一种处理程序运行时错误的有效机制。本章节将对C++标准异常处理机制做基础性的介绍,让我们从宏观上理解异常处理的基本概念、结构以及其在代码中的应用。异常处理能够使程序在遇到错误时跳转到相应的错误处理代码块,而不需要在代码中手动检测每一个可能的错误。这不仅使代码结构更加清晰,也提高了程序的健壮性。我们将从以下几个方面来展开介绍:异常处理机制的基本原理:异常对象、异常处理栈展开。C++异常与函数的返回值、错误码的比较:更清晰、更易于管理的错误处理方式。 阅读详情

相关推荐

ATM火控电容改造实战:提升速凌无刷电机动力与系统稳定性

在嵌入式系统与电机驱动领域,电源完整性是保障电路稳定运行的核心基础。其核心原理在于通过合理的电容网络设计,为负载提供瞬时大电流并滤除高频噪声,从而维持电压稳定。这项技术的核心价值在于能显著提升系统的动态响应能力与可靠性,避免因电压跌落导致微控制器复位或功率器件过应力。典型的应用场景包括无人机电调、机器人关节驱动以及各类需要快速响应的伺服系统。本文聚焦于水弹发射器ATM火控系统的硬件迭代,通过详解电容的选型、布局与焊接流程,特别是针对速凌五代无刷电机的高启动电流特性,系统性地阐述了如何通过强化电源储能与芯片去

weixin_33868027的博客 556

Windows内核驱动中C++异常处理(vcrtl)原理与实践指南

C++异常处理是现代编程中管理错误和资源的核心机制,它通过try/catch/throw语法将错误处理与业务逻辑分离,提升代码可读性和健壮性。其原理基于栈展开和异常对象传递,在用户态由运行时库支持。然而在Windows内核驱动开发中,传统C++异常因依赖用户态运行时而无法使用,开发者只能依赖返回值检查和SEH,导致代码冗长且易错。vcrtl项目通过重新实现异常展开和帧处理器,使内核驱动支持原生C++异常,其技术价值在于提供更清晰的错误处理范式,尤其适用于内存分配失败、硬件访问超时等罕见但严重的错误场景。本文

weixin_32175665的博客 264

别再为数据发愁:5分钟理解事件相机原理,并自己动手生成事件图像

本文深入浅出地解析了事件相机的工作原理,并提供了从静态图像生成事件数据的实用方法。通过Python代码示例,读者可以快速掌握如何模拟事件相机的输出,应用于机器人导航、自动驾驶等领域,解决数据获取难题。

weixin_31458015的博客 300

C++编译时报错 error: unknown type name ‘ ‘

今天项目中,遇到一个很奇怪的问题,明明导入了头文件,却一直说不知道该类型。 如类VideoInfo 类存储的是视频 的信息参数,它当作参数,传入 解码器,作为解码器的成员变量,如下: #include <cstdint> #include "IDecode.h" extern "C"{ #include "libavformat/avformat.h" #include "libavcodec/avcodec.h" }; class VideoInfo { public: .

feikudai8460的博客 1万+

毫米波与太赫兹:十射线模型建模

Pt=1,只考虑地面和前后两面墙的反射,反射系数为0.7。用matlab设计程序并实现该功能。,总计考虑10条路径,求出接收功率随。

SupermarketX的博客 785

人形机器人硬件开发:骨架系统设计全攻略

本文以人形机器人骨架系统为核心研究对象,系统解析其从理论建模到工程实现的全流程设计方法。通过融合刚体力学、材料科学与机器人控制理论,构建"概念基础-理论框架-架构设计-实现机制-实际应用-高级考量-综合拓展"的七层分析体系。重点覆盖运动学/动力学建模、轻量化结构设计、关节模块集成、多物理场耦合优化等关键技术,结合波士顿动力Atlas、本田ASIMO等经典案例,提供从原型设计到量产验证的工程实践指南。

AI天才研究院 1876

[c++]记录Windows程序“应用程序错误”到异常日志

客户反应,程序在运行中经常发生“非法操作”的错误,0x00XXXXXX的内存不能为读之类的错误。这断代码的作用就是 将这些 异常 保存到日志文件, 对照MAP文件可以找到源代码的出错行。#include "Shlwapi.h"#pragma comment( lib,"Shlwapi.lib") #include std::vector g_vErrCode;CString GetNow()

.NET博文收藏 610

【用unity实现100个游戏之10】复刻经典俄罗斯方块游戏(附项目源码)

当今游戏产业中,经典游戏的复刻一直是一项受欢迎且具有挑战性的任务。俄罗斯方块是一个深入人心、令人上瘾的经典游戏,在过去几十年里一直享有广泛的流行度。其简单而富有策略性的玩法吸引了无数玩家的关注。因此,我决定利用Unity引擎来复刻这款经典游戏,以让更多的人重新体验其中的乐趣。通过使用Unity引擎,我能够利用其强大的工具和功能,从头开始构建一个与原版俄罗斯方块游戏相似的游戏。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2795

利用 SEH 机制 Exploit it

有漏洞的源码: #include<windows.h> #include<string.h> #include<stdio.h> void test(char *str) { char buf[8]; strcpy(buf,str); } int main() { FILE *fp; int i; char str[30000]; LoadLib...

新博客:https://aping-dev.com/ 1439

【补充篇】三万字了解AUTOSAR软件架构(一)

主要讲解了AUTOSAR软件架构的分层及各个栈的作用

weixin_47571898的博客 1119

全志A133的AndroidSDK

本小节来学习如何下载全志安卓SDK,SDK的目录,编译和烧录提示:以下是本篇文章正文内容,下面案例可供参考以上就是整个SDK的目录和编译烧录,目的在于让初学者快速了解整个源码的目录和编译出镜像喜欢就订阅吧。

qq_24093081的博客 4054

异常记录(CPU产生的异常和软件模拟产生的异常)

前奏 当API函数3环进0环时,第一件事就是保存现场,保存到_Trap_Frame 异常的分类 CPU产生的异常 错误首先肯定被CPU先发现,然后CPU就会执行相应的错误处理程序 软件模拟产生的异常 throw 1 异常产生 CPU异常的产生 CPU指令检测到异常(例:除0)------>查IDT表,执行中断处理函数--------->CommonDispatchException------>KiDispatchException 在跳转CommonDispatchExcepti

寻梦&之璐 1284

QGis软件 —— 1、Windows10下载安装QGis及插件

QGis —— 1、Windows10下载安装QGis及插件

5159

linux C下struct定义类的error:“unknown type name"

今天本来已经把其他输出输入输出的地方调通了,但是遇到了这个问题,无论我这个定义的struct是在.c文件的上面,或者是被包含的.h文件中,都显示error:“unknown type name" struct _ksw_data { int * qlen; uint8_t *query; int * tlen; uint8_t * target; int m; int8_t *mat;...

轩令的技术博客 4万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Windows 系统编程初探 (四)结构化异常处理之一:SEH的基本原理与进程相关异常处理

        上面的内容只是一些基础知识,虽然简单,但有必要了解一下。现在,我将正式开始我的第一个专题:结构化异常处理(SEH)。SEH 是 Windows 系统提供的功能,跟开发工具无关。值得一提的是,VC 将 SEH 进行了封装,也就是我们平常用到的 __try{}__except(){} 和 __try{}__finally{},我没有研究过它的实现方法,这里也不进行讨论,而我将要讲述的是

xlt123的专栏 2239

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

TypeScriptCompiler异常处理机制:Windows SEH与Linux异常处理的实现原理

TypeScriptCompiler是基于LLVM的TypeScript编译器,它在不同操作系统平台上实现了差异化的异常处理机制。本文将深入解析其在Windows系统采用的结构化异常处理(SEH)和Linux系统使用的异常处理实现原理,帮助开发者理解跨平台异常处理的核心技术。 ## 异常处理模块架构 TypeScriptCompiler的异常处理功能主要通过`TypeScriptExcepti

gitblog_01192的博客 1023

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Windows异常处理核心原理(1)--- 理论篇

                           Windows异常处理核心原理理论篇 前言 这里简单说一下此篇文章应该怎么看,Windows下的异常处理相对来说不是很复杂,但是内容还是蛮多的。也因此呢这个文章也应该是一个系列的开头;在这一篇文章中,我会大概的讲述Windows下异常的处理流程,是一个大概的内容,更详尽的内容留在后面的章节慢慢来说。 理论篇篇幅应该较长,想要详细了解流程的...

星空漫步者 1441

Windows结构化异常处理(SEH)深度解析:从原理到实践

Windows结构化异常处理(SEH)是系统底层的异常处理机制,分为硬件异常(如访问违规、除零)和软件异常。SEH通过链式结构(_EXCEPTION_REGISTRATION_RECORD)处理异常,每个线程都有一个异常处理链。异常分发时系统会遍历此链,直到找到合适的处理器。开发中可使用__try/__except编译器扩展语法实现保护,通过异常过滤器(GetExceptionCode)决定处理方式。高级应用可手动操作SEH链,修复上下文实现异常恢复。理解SEH对编写健壮程序和逆向分析至关重要。

caowei880123的专栏 972

Windows异常处理

异常机制,就是为了让计算机能够更好的处理程序运行期间产生的错误,从编程的角度来看,能够将错误的处理与程序的逻辑分隔开。使得我们可以集中精力开发关键功能,而把程序可能出现的异常统一管理。 Windows提供了异常处理的机制,使得你有机会挽救自己即将崩溃的程序,大体上来说它提供了以下处理异常的机制: SEH-结构化异常处理 VEH-向量化异常处理 VCH-向量化异常处...

liaozhilong88的博客 944

windows异常处理

文章目录中断和异常异常分类windows异常处理SEHtry+finallyexceptUEHVEHVCH顺序 中断和异常 注意,两者谁也不包含谁。 中断由外部硬件产生。如敲键盘、点鼠标。并且这是异步事件(可不处理)。 异常是指cpu内部问题,是一个同步事件(必须处理)。 总之,cpu外部中断简称中断,cpu内部中断就叫异常。 外部中断由pic控制(与if有关),中断发生时,cpu从pic读取两...

Starr 783

深入Windows线程心脏:从TEB结构看SEH异常处理与线程本地存储(TLS)的实现原理

本文深入解析Windows线程环境块(TEB)的核心结构及其在SEH异常处理与线程本地存储(TLS)中的关键作用。通过详细分析TEB的内存布局、SEH链实现原理和TLS存储机制,揭示Windows线程管理的底层逻辑,帮助开发者编写更高效、安全的系统级代码。

weixin_42520025的博客 360

Windows核心编程笔记-Windows提供的结构化异常处理(SEH)

Windows提供的结构化异常处理(SEH)   1.结束处理主要是由编译器来实现,异常处理操作系统实现的要多一些   2.当异常块出现时,编译器要生成特殊的代码,并且生成一些表结构来处理SEH,另外还要生成     一些回调函数   3.SEH与C++的异常处理不同一、结束处理   1.使用形式   _try   {     //processing   }    _finally   {   

moonson的专栏 778

Windows系统编程(六)异常处理

在Windows下,有两种异常:1.结构化异常 SEH2.向量化异常 VEH接下来我们学习这两种异常。

2301_78838647的博客 1656

第八章——Windows下异常处理-异常处理基本概念

前言: 中断和异常的区别,中断是由外部硬件设备或异步事件产生的。异常是由内部事件产生,可以分为故障,陷阱和终止三类。 由CPU引发的异常成为硬件异常,例如访问一个无效的内存地址。由操作系统或应用程序引发的异常成为软件异常。 我们也可以主动抛出一个异常,通过RaiseException()函数 void WINAPI RaiseException( _In_DWORD...

weixin_30739595的博客 252

结构化异常处理SEH

结构化异常处理(seh)(Z)毕业的事情终于要搞定了,几个月前就答应要写这么一个文章,现在补上.结构化异常处理是一种操作系统提供的机制, 用来优化程序的结构,提供更加健壮的程序执行环境.试想想你写程序不用考虑哪里有个内存访问错误,哪里有个空指针等等一类的错误,一直按照程序的逻辑结构 向下写,而不用去检查函数是否成功,这会是多么愉悦的事情(这个乃是seh的宣传词,不代表我的观点,这里

rageliu的专栏 1294
上一篇: Vue同级组件的通信
下一篇: 从源码构建Kubernetes环境
IT回忆录
博客等级 码龄16年 42粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值