使用Windbg调试目标进程排查C++软件异常的一般步骤与要点分享

news2025/2/25 13:28:07

目录

1、概述

2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序

2.1、将Windbg附加到已经启动起来的目标进程上

2.2、用Windbg启动目标程序

2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去

3、分析实例说明

4、分析测试程序的崩溃

4.1、启动程序,将Windbg附加到目标进程上

4.2、使用Windbg初步分析崩溃

4.3、找到相关模块的pdb文件,设置到Windbg中

4.4、加载pdb后查看包含完整信息的函数调用堆栈

4.5、设置C++源代码的路径,Windbg会自动跳转到源代码对应的行号上

4.6、有时需要查看函数中变量的值去辅助分析

4.7、使用.dump命令导出包含异常上下文的dump文件

4.8、可以在Windbg中进行断点调试

5、最后 


C++软件异常排查从入门到精通系列教程(核心精品专栏,订阅量已达600多个,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(重点专栏,专栏文章已更新500多篇,订阅量已达数百个,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到实战(重点专栏,专栏文章已更新300多篇,欢迎订阅,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585分析C++软件问题的实用软件与高效工具实战案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html       软件运行过程中发生的部分崩溃或闪退,软件中安装的异常捕获模块可能是捕获不到的,这种情况下就需要尝试使用Windbg进行动态调试了。前面我们已经讲了使用Windbg静态分析dump文件的完整过程,今天我们再来详细讲述一下如何使用Windbg对目标进程进行动态调试

1、概述

       软件运行过程中发生的大多数崩溃或闪退,软件中安装的异常捕获模块(比如CrashRpt)都能捕获到,都会自动生成包含异常上下文的dump文件。我们只需要事后取来dump文件,然后用Windbg打开进行静态分析就可以了。

       但有少部分崩溃或闪退,异常捕获模块是捕获不到的,或者是捕获到后产生了二次崩溃,没有生成dump文件,也就无法使用Windbg进行静态分析了。这个时候就需要使用Windbg进行动态调试了。将Windbg附加到目标进程上,即Windbg跟着目标进程一起运行,一旦目标进程发生异常,作为正在调试的调试器Windbg能第一时间感知到并中断下来,然后使用kn/kv/kp命令查看到崩溃时的函数调用堆栈,就能进行分析排查了。

       如何将Windbg附加到进程上动态调试呢?主要有两种方式

1)目标程序已经启动,直接将Windbg附加到该目标进程上;

2)直接使用Windbg启动目标程序,这种方式的好处是,能直接从程序启动时就开始调试程序。相对于第一种方式,能监测到程序的启动过程。

       使用Windbg进行动态调试的操作步骤很简单,但很多刚入门的新人可能不太清楚,所以本文中我们将以一个崩溃实例来详细介绍一下整个操作过程(见文章的后半部分)。

       关于Windbg的下载安装及详细介绍,可以查看我之前写的文章:
Windbg使用详解https://blog.csdn.net/chenlycly/article/details/120631007      关于Windbg的命令汇总,可以查看我之前写的文章:

Windbg调试命令汇总https://blog.csdn.net/chenlycly/article/details/51711212

2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序

       要使用Windbg动态调试,要将Windbg关联到目标进程上,可以先将程序启动起来,然后将Windbg附加到目标进程上;也可以用Windbg启动目标程序。两种方式的操作步骤与使用场景略有不同。

2.1、将Windbg附加到已经启动起来的目标进程上

        如果目标程序已经启动,则可以将Windbg附加到进程上。打开Windbg,点击菜单栏File->Attach to a Process...,如下所示:

在打开的窗口中,在进程列表中找到目标程序,点击确定,完成进程的附加:

一般后启动的进程,在进程列表最下面。

       当程序发生卡死或者弹出系统报错框时,再去附加到进程可能也不晚的,也能查看到有用的信息。如果客户环境安全保密等级比较高,不能远程过去,没法使用Windbg去分析,可以在此时打开任务管理,在进程列表中找到目标进程,点击右键,在弹出的右键菜单中点击“创建转储文件”菜单项:

将进程的全dump文件导出到文件中,然后取来这个dump文件再进行分析。关于如何使用Windbg静态分析dump文件,我们之前已经讲过了,可以查看:

使用Windbg分析dump文件排查C++软件异常的一般步骤与要点分享https://blog.csdn.net/chenlycly/article/details/130873143


        在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到600多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,已经更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达300多个,专栏文章已经更新到500多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。

专栏3:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


2.2、用Windbg启动目标程序

       有时程序异常崩溃发生在程序启动的过程中,在启动程序后再将Windbg附加到进程上就为时已晚了,可能程序启动时就崩溃了,根本没有机会去附加调试的。当然我们可以在程序初始化时调用MessageBox弹出模态框将程序阻塞住,给Windbg附加到进程创造时机。以前我们在讲Visual Studio附加到进程调试时,可以使用此方法。对于Windbg动态调试,不必这么做的,可以直接使用Windbg启动程序,这样就能从程序启动时就去监测程序了。

       打开Windbg,点击菜单栏File->Open Executable...,如下所示:

找到目标程序的路径打开目标程序即可。

2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去

       将WIndbg附加到进程上成功,或者使用Windbg将目标程序启动起来后,Windbg会自动中断一次:

 输入g命令将此次中断跳过去即可。让Windbg跟着目标进程一起跑,如果目标进程运行过程中产生了异常,则调试器Windbg会第一时间感知到,并中断下来,此时可以去查看函数调用堆栈去分析了。

       至于为什么将Windbg附加到目标进程成功后会触发一个中断呢?原因是这样子的:

应用层调用DebugActiveProcess发起调试,操作系统会触发int 3中断,这个中断会分发给当前的调试器Windbg,Windbg就产生了一个中断,在Windbg中能看到ntdll!DbgBreakPoint函数的调用!

3、分析实例说明

       为了讲述Windbg动态调试的完整过程,我们使用Visual Studio创建了一个基于MFC框架的对话框工程,在对话框中添加了一个测试按钮:

我们在测试按钮的响应函数中故意添加一段会崩溃的代码,如下所示:

// 添加的一段测试代码
SHELLEXECUTEINFO *pShExeInfo = NULL;
int nVal = pShExeInfo->cbSize; // 通过空指针访问结构体成员,导致崩溃
 
CString strTip;
strTip.Format( _T("nVal=%d."), nVal );
AfxMessageBox( strTip );

代码中使用到的结构体SHELLEXECUTEINFO, 定义如下:

typedef struct _SHELLEXECUTEINFOW
{
    DWORD cbSize;               // in, required, sizeof of this structure
    ULONG fMask;                // in, SEE_MASK_XXX values
    HWND hwnd;                  // in, optional
    LPCWSTR  lpVerb;            // in, optional when unspecified the default verb is choosen
    LPCWSTR  lpFile;            // in, either this value or lpIDList must be specified
    LPCWSTR  lpParameters;      // in, optional
    LPCWSTR  lpDirectory;       // in, optional
    int nShow;                  // in, required
    HINSTANCE hInstApp;         // out when SEE_MASK_NOCLOSEPROCESS is specified
    void *lpIDList;             // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLIST
    LPCWSTR  lpClass;           // in, valid when SEE_MASK_CLASSNAME is specified
    HKEY hkeyClass;             // in, valid when SEE_MASK_CLASSKEY is specified
    DWORD dwHotKey;             // in, valid when SEE_MASK_HOTKEY is specified
    union                       
    {                           
        HANDLE hIcon;           // not used
#if (NTDDI_VERSION >= NTDDI_WIN2K)
        HANDLE hMonitor;        // in, valid when SEE_MASK_HMONITOR specified
#endif // (NTDDI_VERSION >= NTDDI_WIN2K)
    } DUMMYUNIONNAME;           
    HANDLE hProcess;            // out, valid when SEE_MASK_NOCLOSEPROCESS specified
} SHELLEXECUTEINFOW, *LPSHELLEXECUTEINFOW;
 
 
#ifdef UNICODE
typedef SHELLEXECUTEINFOW SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOW LPSHELLEXECUTEINFO;
#else
typedef SHELLEXECUTEINFOA SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOA LPSHELLEXECUTEINFO;
#endif // UNICODE

       在测试代码中定义了SHELLEXECUTEINFO结构体指针变量pShExeInfo,并初始化为NULL,然后并没有给该指针赋一个有效的结构体对象地址,然后使用指针变量pShExeInfo访问结构体的cbSize成员的内存,因为pShExeInfo中的值为NULL,所以结构体cbSize成员的内存地址是结构体对象起始地址的偏移,因为结构体对象地址为NULL,cbSize成员位于结构体的首位,所以cbSize成员就是结构体对象的首地址,就是NULL,所以就访问了64KB小地址内存块,触发了访问小地址 内存区的异常,引发内存访问违例,导致程序发生崩溃闪退。

4、分析测试程序的崩溃

4.1、启动程序,将Windbg附加到目标进程上

       下面我们就以上面讲到的测试程序为例,讲解一下使用Windbg动态调试的完整过程。测试程序如下:

在Button1按钮的响应函数中故意添加了一段会引发崩溃的代码,代码上面已经给出并进行讲解了。

       启动程序后,打开Windbg,点击菜单栏File->Attach to a Process...,在进程列表中找到TestDlg.exe:

点击OK按钮即完成附加。

       完成附加操作后,Windbg会自动中断下来,如下所示:

目标程序会因Windbg的中断被挂起,此时目标程序是没法操作的。此时需要在最下面的命令输入框中输入命令g,按下回车键,执行该命令,让Windbg跳过该中断,让目标程序恢复运行。这样目标程序就可以操作了。

4.2、使用Windbg初步分析崩溃

         点击程序窗口的Botton1的响应函数,即去运行引发崩溃的代码,程序产生异常,Windbg会感知到异常并中断下来,如下所示:

从输出的信息中可以看到,程序发生了Acess violation内存访问违例的异常,并可以看到崩溃时的eax、ebx等各个寄存器中的值,并能看到发生崩溃的那条汇编指令。

       程序最终是崩溃在某条汇编指令上,从汇编指令中我们可以看出是访问了0x0000000内存地址,在Windows系统中小于64KB的内存是禁止访问的。这块禁止访问的内存地址,是Windows系统故意预留的一块小地址内存区域,是为了方便程序员定位问题使用的。一旦访问到该内存区就会触发内存访问违例,系统就会强制将进程强制结束掉。

       关于64KB禁止访问的小地址内存区域,在《Windows核心编程》一书中内存管理的章节中,有专门的描述,相关截图如下所示:

4.3、找到相关模块的pdb文件,设置到Windbg中

       仅仅通过查看崩溃时的各个寄存器的值以及发生崩溃的那条汇编指令是远远不够的,我们一般还需要查看崩溃时的函数调用堆栈。于是我们在Windbg中输入kn命令查看崩溃时的函数调用堆栈,如下所示:

       查看函数调用堆栈的命令,除了kn之外,还有kv和kp,使用kv可以查看到调用函数时的参数信息,如下:

       从函数调用堆栈的最后一帧调用的函数来看,程序的崩溃是发生在TestDlg.exe文件模块中,不是其他的dll模块。显示的函数地址是相对TestDlg.exe文件模块起始地址的偏移,为啥看不到模块中具体函数名称呢?那是因为Windbg找不到TestDlg.exe对应的pdb文件,pdb文件中包含对应的二进制文件中的函数名称及变量等信息,Windbg加载到pdb文件才能显示完整的函数名。

       如何才能找到TestDlg.exe文件对应的pdb文件?我们可以通过查看TestDlg.exe文件的时间戳找到文件的编译时间,通过编译时间找到文件对应的pdb文件。在Windbg中输入lm vm TestDlg*命令,可以查看到TestDlg.exe文件的详细信息,其中就包含文件的时间戳:(当前的lm命令中使用m通配符参数,所以在TestDlg后面加上了*号)

可以看到文件是2023年5月27日17点11分41秒生成的,就可以找到对应时间点的pdb文件了。

在很多公司的正式项目中,一般是通过自动化软件编译系统,每天都会自动编译软件版本,并将软件的安装包及相关模块的pdb文件保存到文件服务器中,如下所示:

这样软件的版本就维护起来了,包含软件的安装包和pdb文件等,这样我们就可以根据模块的编译时间找到对应版本的pdb文件了。

       我们找到了TestDlg.exe对应的pdb文件TestDlg.pdb,将其所在的路径设置到Windbg中。点击Windbg菜单栏中的File->Symbol File Path...,打开设置pdb文件路径的窗口,将pdb文件的路径设置进去,如下所示:

点击OK按钮之前,最好勾选上Reload选项,这样Windbg就会去自动加载pdb文件了。但有时勾选了该选项,好像不会自动去加载,我们就需要使用.reload /f TestDlg.exe命令去让Windbg强制去加载pdb文件(命令中必须是包含文件后缀的文件全名)。

       关于pdb符号库文件的详细说明,可以查看我之前写的文章:

pdb符号库文件详解https://blog.csdn.net/chenlycly/article/details/125508858       设置完成后,我们可以再次运行lm vm TestDlg*命令去看看pdb文件有没有加载进来:

如果已经加载进来,则会在上图中的位置显示出已经加载进来的pdb文件的完整路径。,如上所示。

4.4、加载pdb后查看包含完整信息的函数调用堆栈

       加载到TestDlg.exe文件对应的pdb文件之后,我们再次执行kn命令就可以包含具体的函数名及及代码的行号信息了,如下:

0:000> kn
 # ChildEBP RetAddr      
00 009eebf8 785ef632     TestDlg!CTestDlgDlg::OnBnClickedButton1+0x67 [c:\users\administrator\desktop\testdlg-空指针演示-2\crashdemo_testdlg\testdlg\testdlgdlg.cpp @ 489
01 009eec3c 785efd7a     mfc100ud+0x30f632
02 009eeca0 78649ac3     mfc100ud+0x30fd7a
03 009eecdc 78726c54     mfc100ud+0x369ac3
04 009eed40 783a977a     mfc100ud+0x446c54
05 009eed54 78725859     mfc100ud+0xc977a
06 009eeec4 787257a2     mfc100ud+0x445859
07 009eeee4 78721cf3     mfc100ud+0x4457a2
08 009eef64 787222e6     mfc100ud+0x441cf3
09 009eef84 7850ad0b     mfc100ud+0x4422e6
0a 009eefc0 77b8139b     mfc100ud+0x22ad0b
WARNING: Stack unwind information not available. Following frames may be wrong.
0b 009eefec 77b7836a     USER32!AddClipboardFormatListener+0x4b
0c 009ef02c 77dec81c     USER32!GetClassLongW+0x7aa
0d 009ef0d0 77b77f6a     ntdll!RtlDeactivateActivationContextUnsafeFast+0x9c
0e 009ef134 77b7bb2f     USER32!GetClassLongW+0x3aa
0f 009ef170 77e14f5d     USER32!CallNextHookEx+0x19f
10 009ef1a8 75ca107c     ntdll!KiUserCallbackDispatcher+0x4d
11 009ef1ac 77b778cb     win32u!NtUserMessageCall+0xc
12 009ef210 77b75d8f     USER32!GetSystemMetricsForDpi+0x15cb
13 009ef230 691e6608     USER32!SendMessageW+0x6f
14 009ef250 691e65cd     COMCTL32!CCEnableScrollBar+0x1028
15 009ef268 69225f33     COMCTL32!CCEnableScrollBar+0xfed
16 009ef304 77b8139b     COMCTL32!SetWindowSubclass+0x3963
17 009ef330 77b7836a     USER32!AddClipboardFormatListener+0x4b
18 009ef380 77b7b8e9     USER32!GetClassLongW+0x7aa
19 009ef414 77b760da     USER32!Ordinal2712+0x1c9
1a 009ef488 77b7a2d8     USER32!DispatchMessageW+0x24a
1b 009ef4b8 7875def3     USER32!IsDialogMessageW+0x108

我们看到了具体的函数名CTestDlgDlg::OnBnClickedButton1,还看到了对应的代码行号489。通过这些信息,我们就能到源代码中找到对应的位置了,如下所示:

是访问了空指针产生的异常。当然上面的代码是我们故意这样写的,目的是为了构造一个异常来详细讲解如何使用Windbg进行动态调试跟踪的。

4.5、设置C++源代码的路径,Windbg会自动跳转到源代码对应的行号上

        为了方便查看,我们可以直接在Windbg中设置C++源码路径,这样Windbg会自动跳转到源码对应的位置。点击Windbg菜单栏的File->Source File Path...,将源码路径设置进去:

然后Windbg会自动跳转到对应的函数及行号上:

然后点击函数调用堆栈中每行最前面的数字超链接,就可以自动切换到源码对应的函数中。上图中的函数调用堆栈中很多模块是系统库中的,比如mfc100u、User32等,这些库是系统库,是没有源码的。

4.6、有时需要查看函数中变量的值去辅助分析

       有时我们在排查异常时,需要查看函数调用堆栈中某个函数中的变量值去辅助排查,这些变量的值可能是关键线索。在某些场景下这种操作方式非常有用,我们在项目中多次使用过。可以查看函数中局部变量的值,也可以查看函数所在类对象的this指针指向的类对象中变量的值。我们要查看哪个函数,就点击函数调用堆栈中每一行前面的数字超链接,如下所示:

 我们看到了局部变量pShExeInfo 的值:

我们可以点击this对象的超链接,就能查看当前函数对应的C++类对象中成员变量的值,如下:

       在Windbg中查看变量的值去辅助分析软件异常的实战分析案例,可以查看我之前写的文章:

通过查看Windbg中变量值去定位C++软件异常问题https://blog.csdn.net/chenlycly/article/details/125731044通过查看Windbg中变量值去定位C++软件异常的又一典型案例分享https://blog.csdn.net/chenlycly/article/details/125793532

4.7、使用.dump命令导出包含异常上下文的dump文件

       比如问题出现在客户的电脑上,我们在使用Windbg初步分析后没找出引发崩溃的原因,我们不能长时间占用别人的电脑,我们可以使用.dump命令将包含异常上下文的信息导出到dump文件中,事后让客户将dump文件发给我们,我们在自己的电脑上做进一步的分析排查。

        比如使用.dump /ma D:\0604.dmp命令,将当前的异常信息保存到D:\0604.dmp文件中,命令执行效果如下:

会显示dump文件导出成功。

        这里有两个概念的区别,一个是mini dump文件,一个是全dump文件。我们将windbg附加到进程上使用.dump命令导出的dump文件,是全dump文件,全dump文件中包含了所有的信息,可以查看到所有变量的信息。另外通过任务管理器导出的dump文件:

也是全dump文件。全dump文件因为包含了所有的信息,所以会比较大,会达到数百MB,甚至上GB的大小。但如果通过安装在程序的异常捕获模块CrashReport导出的dump文件就是非全dump文件,是mini dump文件,大概只有几MB左右,因为异常捕获模块捕获到异常后,会自动导出dump文件,保存到磁盘上,如果都导出体量很大的全dump文件,很大量消耗用户的磁盘空间,所以我们会设置生成mini dump文件。

       在异常捕获模块中我们是通过调用系统API函数MiniDumpWriteDump导出dump文件的,我们通过设置不同的函数调用参数去控制生成mini dump文件的。

       关于dump文件的分类与dump文件的生成方式,可以查看我之前写的文章:

dump文件类型与dump文件生成方法详解https://blog.csdn.net/chenlycly/article/details/127991002      另外,Windbg等工具的下载链接如下:

链接:https://pan.baidu.com/s/1ID6_0RSYKbiy_tzfYDX3Ew 
提取码:tn6i

4.8、可以在Windbg中进行断点调试

         Windbg中有多个支持断点调试的命令,比如:

bl:用来显示当前设置的断点;

bp:设置断点;

bc:清除指定序号的断点。

断点调试是个很重要的功能,之前使用过Windbg的断点调试功能解决了多个问题,比如我之前写的一篇案例文章:

在Windbg中设置断点追踪打开C++程序远程调试开关的模块https://blog.csdn.net/chenlycly/article/details/130058430

5、最后 

       本文通过一个异常崩溃实例来详细讲述了使用Windbg动态调试目标进程的一般步骤及完整过程,对于C++软件调试的初学者来说,很有参考价值,希望能给大家要提供一些借鉴或帮助。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304905.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ddd 文章总结分享,ddd实战代码分享, 领域驱动设计java实战源码大全,我看过的ddd java源码

1. 前段时间研究ddd, 收藏了很多相关知识,分享出来,希望能够帮助更多的小伙伴了解ddd, 什么是领域驱动设计,并分享在github发现的开源ddd代码 2. ddd 必须强烈点赞阿里两位大佬,一个为殷浩, 一个为cola作者 2.1.1 殷浩…

什么是MySql的主从复制(主从同步)?

主页还有其他面试题总结,有需要的可以去看一下,喜欢的就留个三连再走吧~ 1.什么是MySql的主从复制原理? 主从复制的核心就是二进制binlog(DDL(数据定义语言)语句和DML(数据操纵语言&#xff09…

蓝桥云课python代码

第一章语言基础 第一节编程基础 1 python开发环境 第一个Python程序 # 打印"Hello World" print("Hello World")# 打印2的100次方 print(2 ** 100)# 打印112 print("11",1 1)""" Hello World 126765060022822940149670320537…

c#丰田PLC ToyoPuc TCP协议快速读写 to c# Toyota PLC ToyoPuc读写

源代码下载 <------下载地址 历史背景与发展 TOYOPUC协议源于丰田工机&#xff08;TOYODA&#xff09;的自动化技术积累。丰田工机成立于1941年&#xff0c;最初是丰田汽车的机床部门&#xff0c;后独立为专注于工业机械与控制系统的公司。2006年与光洋精工&#xff08;Ko…

深入解析-无状态服务-StatefulSet (一)

一、有状态服务 VS 无状态服务 1.无状态服务介绍 1.数据方面&#xff1a;无状态服务不会在本地存储持久化数据.多个实例可以共享相同的持久化数据 2.结果方面&#xff1a;多个服务实例对于同一个用户请求的响应结果是完全一致的 3.关系方面&#xff1a;这种多服务实例之间是…

hackmyvm-buster

题目地址 信息收集 主机发现 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -I eth1 192.168.56.0/24 Interface: eth1, type: EN10MB, MAC: 00:0c:29:34:da:f5, IPv4: 192.168.56.103 WARNING: Cannot open MAC/Vendor file ieee-oui.txt: Permission denied WARNING: C…

【原创】Windows11安装WSL“无法解析服务器的名称或地址”问题解决方法

原因分析 出现这个问题一开始以为WSL设置了某个服务器&#xff0c;但是通过运行 nslookup www.microsoft.com 出现下面的提示 PS C:\Windows\system32> nslookup www.microsoft.com 服务器: UnKnown Address: 2408:8000:XXXX:2b00:8:8:8:8非权威应答: 名称: e13678…

网页制作08-html,css,javascript初认识のhtml使用框架结构,请先建立站点!

框架一般由框架集和框架组成。 框架集就像一个大的容器&#xff0c;包括所有的框架&#xff0c;是框架的集合。 框架是框架集中一个独立的区域用于显示一个独立的网页文档。 框架集是文件html&#xff0c;它定义一组框架的布局和属性&#xff0c;包括框架的数目&#xff0c;框架…

【Vscode 使用】集合1

一、使用make工具管理工程 windows下&#xff0c;下载mingw64&#xff0c;配置好mingw64\bin 为 Win10系统全局变量后。 在mingw64/bin目录下找到mingw32-make.exe工具。复制一份改名为&#xff1a;make.exe&#xff0c;没错&#xff0c;就是那么简单&#xff0c;mingw64自带m…

文章精读篇——用于遥感小样本语义分割的可学习Prompt

题目&#xff1a;Learnable Prompt for Few-Shot Semantic Segmentation in Remote Sensing Domain 会议&#xff1a;CVPR 2024 Workshop 论文&#xff1a;10.48550/arXiv.2404.10307 相关竞赛&#xff1a;https://codalab.lisn.upsaclay.fr/competitions/17568 年份&#…

解决 kubeasz 安装k8s集群跨节点pod 无法使用cluster ip通讯问题

问题描述 使用kubeasz搭建k8s集群后使用的配置文件 # etcd cluster should have odd member(s) (1,3,5,...) [etcd] 192.168.xx.22# master node(s) [kube_master] 192.168.xx.22# work node(s) [kube_node] 192.168.xx.9 192.168.xx.22# [optional] harbor server, a privat…

Docker 搭建 Nginx 服务器

系列文章目录 Docker 搭建 Nginx 服务器 系列文章目录前言一、准备工作二、设置 Nginx 容器的目录结构三、启动一个临时的 Nginx 容器来复制配置文件四、复制 Nginx 配置文件到本地目录五、删除临时 Nginx 容器六、创建并运行 Nginx 容器&#xff0c;挂载本地目录七、修改 ngin…

Spring AI + 大模型开发应用

JAVA SpringAI 大模型开发AI应用DEMO 前言JAVA项目创建示例 前言 在当今快速发展的技术领域&#xff0c;人工智能&#xff08;AI&#xff09;已经成为推动创新和变革的重要力量。然而&#xff0c;AI应用的开发过程往往复杂且耗时&#xff0c;需要开发者具备深厚的技术背景和丰…

【C++11】 并发⽀持库

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 前言&#xff1a;&#x1f680; 并发⽀持库一&#xff1a;&#x1f525; thread库 二&#xff1a;&#x1f525; this_thread 三&#xff1a;&#x1f525; mutex 四&#xff1…

Windows 11【1001问】如何下载Windows 11系统镜像

随着科技的不断进步&#xff0c;操作系统也在不断地更新换代。Windows 11作为微软最新一代的操作系统&#xff0c;带来了许多令人兴奋的新特性与改进&#xff0c;如全新的用户界面、更好的性能优化以及增强的安全功能等。对于想要体验最新技术或者提升工作效率的用户来说&#…

视觉分析之边缘检测算法

9.1 Roberts算子 Roberts算子又称为交叉微分算法&#xff0c;是基于交叉差分的梯度算法&#xff0c;通过局部差分计算检测边缘线条。 常用来处理具有陡峭的低噪声图像&#xff0c;当图像边缘接近于正45度或负45度时&#xff0c;该算法处理效果更理想。 其缺点是对边缘的定位…

深度学习-6.用于计算机视觉的深度学习

Deep Learning - Lecture 6 Deep Learning for Computer Vision 简介深度学习在计算机视觉领域的发展时间线 语义分割语义分割系统的类型上采样层语义分割的 SegNet 架构软件中的SegNet 架构数据标注 目标检测与识别目标检测与识别问题两阶段和一阶段目标检测与识别两阶段检测器…

【大模型】蓝耘智算云平台快速部署DeepSeek R1/R3大模型详解

目录 一、前言 二、蓝耘智算平台介绍 2.1 蓝耘智算平台是什么 2.2 平台优势 2.3 应用场景 2.4 对DeepSeek 的支持 2.4.1 DeepSeek 简介 2.4.2 DeepSeek 优势 三、蓝耘智算平台部署DeepSeek-R1操作过程 3.1 注册账号 3.1.1 余额检查 3.2 部署DeepSeek-R1 3.2.1 获取…

《计算机视觉》——图像拼接

图像拼接 图像拼接是将多幅有重叠区域的图像合并成一幅全景或更大视角图像的技术&#xff0c;以下为你详细介绍&#xff1a; 原理&#xff1a;图像拼接的核心原理是基于图像之间的特征匹配。首先&#xff0c;从每幅图像中提取独特的特征点&#xff0c;如角点、边缘点等&#x…

element实现需同时满足多行合并和展开的表格

element实现需同时满足多行合并和展开的表格 需求描述: 以下面这张图为例&#xff0c;此表格的“一级表格”这一行可能存在多行数据&#xff0c;这种情况下需要将“一级指标”&#xff0c;“一级指标扣分xxx”,“一级指标关联xxx”这三列数据的行展示根据后面数据&#xff08…