使用Windbg动态调试目标进程的一般步骤及相关要点详解

news2025/1/14 0:45:28

目录

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文件

5、最后 


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具案例集锦(专栏文章正在更新中...)https://blog.csdn.net/chenlycly/category_12279968.html       软件运行过程中发生的部分崩溃或闪退,在软件中安装的异常捕获模块是捕获不到的,这种情况下就需要尝试使用Windbg进行动态调试了。前面我们已经讲了Windbg静态分析dump文件的完整过程,今天我们就来详细讲述一下如何使用Windbg对目标进程进行动态调试。

1、概述

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

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

       其实使用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文件的一般步骤详解https://blog.csdn.net/chenlycly/article/details/130873143

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

可以看到文件是2023年5月27日17点11分41秒生成的,就可以找到对应时间点的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++类对象中成员变量的值,如下:

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

5、最后 

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

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

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

相关文章

ModuleNotFoundError: No module named ‘transformers_modules.chatglm-6b_v1‘的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

ggplot2、RMySQL、httpuv、shiny、miniUI、devtools、recharts安装问题

目录 ggplot2下载成功! RMySQL下载成功! automake-1.16.tar.gz下载成功! httpuv下载成功! shiny下载成功! miniUI下载成功! devtools下载成功! recharts下载成功! 首先的首先…

shiro 550 反序列化rce

Apach shiro 是一款开源安全框架,提供身份验证,授权,会话管理等。 shiro 550 反序列化漏洞rce 通关利用它反序列化的漏洞直接执行rce 加密的用户信息序列化后储存在名为remenber -me的cooike中。攻击者可以使用shiro默认密钥伪造cooike&am…

django连接mysql一些报错解决方法

1.AttributeError: str object has no attribute ‘decode’ 2.django.db.utils.OperationalError: (2003, "Can’t connect to MySQL server on ‘localhost’ ([WinError 10] 解决方法:仔细核对#数据库引擎和#数据库的主机地址 DATABASES { ‘default’:…

2023PS beta 官方注册安装教程

该教程为官方注册下载教程,无风险。 软件介绍 Adobe Photoshop 2023版(简称PS)是一款全球流行的专业图像处理软件及照片和设计软件。Adobe Photoshop中文版是Adobe Creative Cloud 创意云桌面程序中心的图形设计软件热门产品,它是平面设计领域和数字图象…

读改变未来的九大算法笔记03_纠错码

1. 真正根源 1.1. 在电报和电话等通信系统中出现的 1.2. 理查德汉明创造了第一批纠错码:一种近乎神奇的能侦测并纠正计算机数据中错误的算法 2. 信息理论学的一部分 2.1. Information Theory 2.2. 香农通过数学展示了有可能从根本上通过一个嘈杂的、引发错误的…

每日学术速递6.1

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.LayoutGPT: Compositional Visual Planning and Generation with Large Language Models 标题:LayoutGPT:具有大型语言模型的组合视觉规划和生成 作者&…

Linux开发工具:gcc和g++

目录 一. 什么是gcc和g 二. gcc的基本使用方法 三. 库和链接 3.1 动态库和静态库 3.2 动态链接和静态链接 四. Debug和Release 五. makefile和make 六. 总结 一. 什么是gcc和g gcc:Linux下编译C语言程序的编译器g:Linux下编译C代码的编译器 由…

Apache网页的优化与安全

文章目录 Apache 网页的压缩Apache的页面缓存Apache页面隐藏版本信息Apache页面设置防盗链 Apache 网页的压缩 检查压缩模块 apachectl -t -D DUMP_MODULES | grep "deflate"安装mod_deflate 模块 如果没有安装mod_deflate 模块,重新编译安装 Apache 添…

嵌入式STM32中时钟系统详细分析

1. STM32的时钟源主要有: 内部时钟 外部时钟 锁相环倍频输出时钟 1.1 详细介绍 HSI(内部高速时钟) 它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入。 HSE(外部高速时钟) 接入晶振范围是4-16MHZ…

深入理解设计原则之组件构建原则【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 组件构建原则 系列文章目录1、组件构建原则的定义和解读1、组件2、组件聚合2.1、复用/发布等同原则(REP)2.2 、共同闭包原则(CCP&…

C++(6):函数

函数基础 典型的函数包括:返回类型、函数名字、由 0 个或多个形参组成的列表以及函数体。 通过调用运算符(call operator)来执行函数。 调用运算符的形式是一对圆括号,它作用于一个表达式,该表达式是函数或者指向函数…

1731_makefile编写小结1_编译同目录下的文件

全部学习汇总: GreyZhang/g_makefile: Learn makefile from all kinds of tutorials on the web. Happy hacking and lets find an common way so we may dont need to touch makefile code any more! (github.com) 欢迎路过的YUAN类朋友相互交流,以下是…

每日学术速递6.2

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.BiomedGPT: A Unified and Generalist Biomedical Generative Pre-trained Transformer for Vision, Language, and Multimodal Tasks 标题:BiomedGPT:用于…

chatgpt赋能python:Python反向99乘法表:简单易学的终极练习

Python反向99乘法表:简单易学的终极练习 Python是一门强大而又容易上手的编程语言,而反向99乘法表则是一个极佳的练手项目。不仅能锻炼Python的基本语法和逻辑思维,同时也能体现出代码的风格和美感。本文将以Python反向99乘法表为例&#xf…

基于matlab仿真L形金属块基于时间温度分布图

一、前言 此示例说明了如何使用 Simulink 3D 动画™和 MATLAB 接口来操作复杂对象。 在此示例中,矩阵类型的数据在 MATLAB 和虚拟现实世界之间传输。使用此功能,您可以实现大量的颜色变化或变形。这对于可视化各种物理过程很有用。 我们在L形金属块中使用…

Chain of Thought Prompting和Zero Shot Chain of Thought初步认识

1. 思维链提示(Chain-of-Thought Prompting) 思维链(Chain-of-Thought:CoT)提示过程是一种最近开发的提示方法,它鼓励大语言模型解释其推理过程。下图显示了 few shot standard prompt(左)与链式思维提示过程(右&…

ChatGPT提示词攻略之基本原则

下面是调用openai的completion接口的函数。但在本文中并不是重点。了解一下就好。 import openai import osfrom dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv())openai.api_key os.getenv(OPENAI_API_KEY)def get_completion(prompt, model"gp…

[LeetCode周赛复盘] 第 348场周赛20230604

[LeetCode周赛复盘] 第 348场周赛20230604 一、本周周赛总结6462. 最小化字符串长度1. 题目描述2. 思路分析3. 代码实现 6424. 半有序排列1. 题目描述2. 思路分析3. 代码实现 6472. 查询后矩阵的和1. 题目描述2. 思路分析3. 代码实现 6396. 统计整数数目1. 题目描述2. 思路分析…

10.全局配置 app.json 与页面配置

常用的配置项有 pages 小程序的所有页面window 小程序窗口的外观tabBar 小程序底部的tabBar效果,就是底部的切换那部分style 组件样式版本 目录 1 window 2 tabBar 3 页面配置 1 window 小程序由下面三个部分组成,window可以配置 导航栏区域 与…