Visual Studio调试C/C++指南

1. 前言

Visual Studio(VS)是微软开发的一款集成开发环境(IDE)软件,支持C/C++、C#、VB、Python等开发语言,开发桌面、Web等应用程序。VS功能极其强大,使用极其便利,用户数量最多,被誉为"宇宙第一IDE"。

熟悉地掌握基于VS的C/C++调试技术,可以大幅提升调试性能。随着VS版本的更新,其功能越来越强大,本文的内容是基于VS2019进行验证测试的,之前版本VS可能有少量特性不支持。

2. 基础

 

2.1. 调试

代码调试主要指使用调试工具来检查和修复代码中的错误和问题。代码调试主要有运行调试、打印调试、内存分析、静态分析、性能分析等。

2.2. 符号文件

符号文件(Symbol File)是指在编译程序时生成的包含调试信息的文件。它们通常与可执行文件或动态链接库(DLL)配对存在,用于提供程序的调试信息。VC生成的符号文件为PDB(Program Database)文件。其中存储变量名、函数名、代码行号、类型信息和栈信息等。exe/dll与pdb文件是一一对应的。每次重新编译代码,都会生成新的pdb。

2.3. 调试器

Microsoft Visual C/C++的调试器名称叫做"Visual Studio Debugger"。在调试exe时,其会读取exe文件中记录的PDB路径信息(这个路径是开发电脑编译时生成的PDB路径),如果这个PDB路径不存在,那么调试器会在exe目录去找PDB,如果依然找不到PDB,则启用无PDB调试。无PDB调试只能查看汇编信息和寄存器信息。

调试方式

3.1. 本地调试

VS工程默认即为本地调试(Local Windows Debugger)。选定启动工程,按F5或通过菜单Debug->Start Debugging。

  • 命令行参数(Command Arguments),给exe配置命令行参数。

  • 附加(Attach),默认No。Yes表示附加当前路径的进程进行调试。

3.2. 远程调试

  1. 将开发电脑上的Remote Debugger目录拷贝到生产电脑。

  1. 根据程序的类型x64/x86打开相应的目录,并打开生产电脑目录下的msvsmon.exe。

  2. 首次调用时,会弹出远程调试配置窗口,勾选所有的允许远程调试器与这些网络通信。

  3. 配置msvsmon.exe的Tools->Options。4015是默认的端口号,一般不建议修改。

  1. 获取生产电脑的IP,局域网网络通信,可以使用计算机名:端口号的方式,也可以使用IP:端口号的方法。但是在访问跨网关的局域网电脑时,计算机名可能无法解析出对应的IP地址,导致访问失败,所以更推荐IP:端口号的访问方式。

  2. 依据下图配置相关信息。

  3. 按F5启动调试,调试远程exe和调试本地exe后续操作完全一致。

3.3.  附加调试

  1. 打开exe。

  2. 从菜单启动Debug->Attach to Process,选择需要调试的进程进行附加。如果是远程进程,配置下图信息。

3.4. 外网调试

远程调试一般是针对局域网进行调试。但是有些时候,问题进程在外地,出差不方便或成本太高,非常需要一种能够穿透广域网进行调试的方法。最简单的方法是使用VPN将目标电脑远程连接到开发电脑,这样目标电脑和开发电脑就相当于处在同一个局域网,就可以使用普通的远程调试来进行外网目标电脑调试。

3.5. DLL调试

在DLL工程的属性中Debugging的Command中选择要执行的exe,然后在dll中设置相关断点。再按F5调试,即会中断在DLL工程的断点处。

4. 断点调试

int 3是x86-64架构CPU上的中断指令,用于在程序执行过程中触发软件中断。VS在给代码添加断点时,就是将指定行对应的代码修改为int 3指令,并且调试器接管代码。继续单步执行时,会还原int 3覆盖的代码。

4.1. 断点类型

4.1.1. 普通断点

在代码指定行按F9或右键菜单Breakpoint->Insert Breakpoint设置普通断点。

4.1.2. 条件断点

在断点上右键选择Conditions。

设置 i == 5, 然后点击Close。按F5执行,代码会停止在断点处,此时i==5。

指定当前断点触发指定次数时中断下来。

当前断点运行在指定线程时才中断下来。

4.1.3. 行为断点

行为断点(Actions Breakpoint),也称Tracepoint,因为断点触发时会在Output窗口打印信息。Continue Code Execution勾选表示不停止在断点处,如果选空表示停止在断点处。

Output窗口显示:The value of z is 0x0000001e. 0x2C74

$PID,是伪指令。可用的伪指令如下:

4.1.4. 数据断点

数据断点(Data Breakpoint),当然变量地址的内容发生改变时,即中断下来。如下图,Address编辑框可以直接填写变量的地址,也可以使用取地址符来获取变量的地址。数据断点只能针对有效数据设置断点,并且只能在已经开始调试之后,在Breakpoint窗口的菜单New->Data Breakpoint来设置。

4.1.5. 系统函数断点

例如想在CreateFile函数中下断点。可以使用dhb.exe在相应的

dbh.exe -s:srv*C:\Symbols*Symbol information -d C:\Windows\SysWOW64\kernel32.dll enum *CreateFile*

然后Breakpoints->New->Function Breakpoint:

运行就会断在系统API函数处,通过调用栈查找到调用的函数。

4.1.6. 软件断点

除了通过VS来添加断点外,我们也可以在代码中主动添加软件断点__debugbreak()/DebugBreak函数,或是断言ASSERT(0)。

__debugbreak()/DebugBreak是代码到此处立即中断,而断言则是根据参数逻辑值来决定是否中断。软件断点主要用来在代码潜在的异常出现时产生中断提示开发者。

4.2. 调试行为

4.2.1. 基本行为

工具栏或Debug菜单或鼠标右键都有调试行为的选项。

  1. Break All,中断当前所有正在执行的代码。当代码进入死循环时,点击Break All,代码即会中断下来,此时遍历线程查看函数调用栈,即能发现死循环代码位置。

  2. Stop Debugging,停止当前调试。

  3. Restart,重新开始调试。

  4. Show Next Statement,光标跳到下一次要执行的代码处。

  5. Step Into,快捷键F11,进入当前语句所调用的函数内部,并停在函数的第一行。如果当前行没有函数调用,则直接运行至下一行。

  6. Step Over,快捷键F10,执行当前语句,但不进入函数内部。

  7. Step Out, 快捷键Shift+F11,执行完当前函数,暂停在函数调用处。

  8. Step Backward,即退回到上一次代码暂停的位置,恢复上次调试的信息。Step Forward,前行到退回前的代码暂停的位置。这是基于栈快照进行的调试,VS会在几次中断时,保存对应栈信息,尤其是当我们想反复调试一个算法时,使用Step Backward会非常方便。

4.2.2. 高级行为

  1. Run To Cursor,运行到光标处中断,可以通过鼠标右键来执行,也可在光标处的代码行的图标上点击。

  1. Force Run To Cursor,强制运行到光标处,会跳过中间设置的断点。

  2. 自定义,鼠标放在箭头上,可以将下一个可执行代码的位置拖动到任意位置。拖动需要依赖先前的代码,否则可能产生异常。

5. 调试窗口

5.1. Output 

Output Debug窗口主要输出调试过程的信息,主要包括:

  • Exception Messages

  • Step Filtering Messages

  • Module Load Messages

  • Module Unload Messages

  • Process Exit Messages

  • Thread Exit Messages

  • Program Qutput

其中Program Output是代码运行时输出的信息,主要通过Trace函数或OutputDebugString函数来将信息输出到Output窗口。如果是非调试状态下,OutputDebugString的输出信息则需要DbgView工具来接收并显示。

5.2. Locals

Locals窗口显示调试时当前执行代码所在函数所在的栈的局部变量的值和类型。

5.3. Autos

Autos窗口显示调试时当前执行代码所在函数所在的栈的上下文栈变量值和类型。

5.4. Watch

Watch窗口总共有4个,可以在菜单Debug->Windows->Wartch中选择。Watch窗口可以显示当前栈内存的局部变量,全局变量等,支持16进制形式显示,并支持实时修改变量值。

支持简单的表达式显示,如x+y, sizeof(x)等。

支持格式化显示,如(int*)(szBuff),4将Buff转换为int*,再格式化为4个元素显示。

Watch窗口还支持显示伪变量,如:

  • $tid – 当前线程的的线程 ID

  • $pid – 进程 ID

  • $cmdline – 附加进程的命令行字符串

  • $user – 运行在程序中的账户信息

  • $registername – 显示指定寄存器的寄存器内容

  • $err – 显示最近错误的错误码

  • $err, hr – 显示最近错误的消息

5.5. Memory

Memory窗口是用来显示地址对应的内容,Memory窗口有4个从菜单Debug->Windows->Memory中选择。

Adress编辑框填写变量地址,Columns选择每行显示的内容数量。

5.6. QuickWatch

QuickWatch窗口是快捷观察、修改变量的窗口。

5.7. Disassembly

参数传递、函数返回等一些复杂的语法形式,要想理解其深层执行逻辑,就需要单步执行汇编代码来观察其隐藏逻辑细节。

5.8. Registers

寄存器窗口,显示当线程的寄存器信息。

5.9. Call Stack

函数调用栈窗口,显示当前线程的函数栈调用情况。可以通过Threads窗口选定当前线程。

5.10. Immediate Window

Debug->Windows->Immediate窗口。立即窗口主要用来查看、修改变量,执行函数,表达式等。

6. 多线程

6.1. Threads

Threads是显示当前进程的所有运行的线程信息的窗口。双击线程所在行,即将当前代码窗口、调用栈窗口等相关窗口的内容更新为选定线程。

当进程有多个工作者线程时,且只想调试其中一个线程时,可以将不关心的线程使用Freeze冰冻起来。冰冻的线程在按F5运行时,依然冰冻着不运行。使用Thaw解冻线程,线程将恢复为正常可以调试的状态。

6.2. 条件断点

在多线程中,根据线程信息来设置相应的断点来观察期望的变量信息。

6.3. Parallel Watch

Debug->Window->Parallel Watch可以显示几个线程同时调用的函数变量的情况,更方便地调试多线程。

6.4. 线程结构图

打开Debug->Windows->Parallel Stack窗口,会显示所有线程的栈,并显示当前线程栈。相比Threads窗口更直观。

7. 参数配置

7.1. 增量链接

增量链接在Debug下默认打开,在Release下默认关闭。通过Linker->General->Enable Incremental Linking来开启和关闭。增量链接还需要配置C/C++->General->Debug Information Format->Program Database for Edit And Continue (/ZI)。

增量链接的用处是在断点单步调试代码的时候,编辑代码,然后继续单步执行时,VS会自动增量链接,不用重新编译源代码,然后继续单步执行代码进行调试。

增量链接是调试时使用,增量编译则是编译时只编译修改的源文件,两者不相同。

7.2. 优化级别

Debug版本下,默认关闭代码优化,此时代码的调试信息与代码源文件是一一对应,调试更方便。Release版本下,默认使用O2优化,此时代码优化程度非常大,调试信息与代码源文件无法一一对应。如果想调试Release版本,则需要关闭优化。

7.3 宏展开

一些复杂的宏,非常难以调试。如何查看宏预处理之后展开形成的代码呢?C/C++->Preporcessor->Preprocess to a File配置默认是关闭的,打开此配置为Yes(/P)表示将生成预处理后的文件,文件与源文件同名,后缀为.i。在.i文件中可以查看所有宏展开的结果,以及其他预处理的结果。

7.4. 显示链接细节

VS 链接器默认只显示一些关键的链接信息。可以通过Linker->General->Show Progress配置Display all progress messages(/VERBOSE)来显示详细的链接信息,可以更方便地分析一些链接异常的错误。

7.5. 警告

7.5.1. 编译警告

为了提升代码的可靠性,警告也需要认真对等。

  • C/C++->All Options->Warning Level,选择合适的警告级别,初期可以选择W3级别。

  • C/C++->All Options->Treat Warning As Errors,初期可以不设置。

  • C/C++->All Options->Treat Specific Warnings As Errors,可以将一些关键警告设置为错误。

7.5.2. 链接警告

Linker->All Options->Treat Linker Warning As Errors,根据需要将警告作为错误对待。

Dump调试

8.1. 概念

Dump文件(Dump File),也叫转储文件,以.DMP为文件后缀。dump文件是进程在内存中的镜像文件,通过转换然后存储成以.DMP后缀的文件。dump文件根据存储时的选项不同,会生成不同大小的文件,其中记录信息也自然有所不同。

8.2. 转储文件生成

  1. 通过Windows进程管理器,选择指定的进程,右键生成转储文件。

  2. 通过函数MiniDumpWriteDump生成转储文件。

8.3. 调试转储文件

  • 选择与生成Dump文件相同版本的VS。

  • 启动VS并打开Dump文件。

  • 必须保证生成Dump文件的程序的PDB文件和源代码相一致。

  • VS2005打开Dump文件时,直接按F5调试,代码会停在出错的地方,通过Call Stack窗口查看。

  • VS2010打开Dump文件时,

需要通过Set symbol paths设置符号文件路径,也即PDB文件路径。然后点击Debug with Native Only,代码即会中断在出错的地方,通过Call Stack窗口查看相关信息。

变量溢出

变量内存溢出分为上溢(Overflow)和下溢(Underflow)。内存溢出导致的异常是C++代码最为难以调试的Bug之一,因为内存溢出导致的异常往往不会立即出现,而是展现在后面的函数中。因为内存溢出可能覆盖了后面的代码,导致后面的代码执行异常。

AddressSanitizer (ASan) 是一种编译器和运行时技术,它通过和编译器配合,通过插桩技术,向内存的前后添加标识,来识别运行时产生的上溢和下溢异常。其对代码执行性能影响较大,VS中默认是关闭的,需要手动打开。

ASan可以识别栈内存、堆内存、静态内存的溢出,另外也能检测重复释放,释放后使用内存。

通过C/C++->General->Enable Address Sanitizer使能,此配置与编辑并继续、增量链接和/RTC不兼容。

更多信息:AddressSanitizer | Microsoft Learn

资源泄露

电脑上的内核资源是有限的,申请使用完了,就要释放,否则资源可能不够用,导致后续申请失败而运行异常。所以资源泄露也是比较严重的问题,需要解决。

10.1. 内存泄露

在调试运行进程时,退出调试后,可能会在VS的Output窗口中显示如下信息:

这就是内存泄露的提示信息。上面的信息有时会指出内存泄露的位置,有的时候指出的位置却不准确。第三方工具 Visual Leak Detector,可以用来检测内存泄露,其主要是通过重载内存申请和释放函数,然后记录内存申请的地址和详细源文件行号,最后退出时检测所有申请的地址是否释放,如果没有释放,则打印出内存申请的信息。

Visual Leak Detector的使用非常简单,下载安装,然后在工程的启动接口文件中添加#include <vld.h>即可。

详细信息见:Home · KindDragon/vld Wiki · GitHub

10.2. 句柄泄露

除了内存泄露外,句柄也是容易泄露的资源。

  • 可以使用WinDbg的句柄快照对比功能找出未正常释放的句柄。

  • 可以使用第三方工具Deleaker,可以注册试用版本使用14天。Deleaker会检测出代码申请未释放的行号。

11. 静态调试

相比于动态调试(在代码运行时调试),静态调试是在代码编译时来调试,其效率更高。

11.1. 静态断言

静态断言static_assert是C++11中引入的新语法,可以在编译时进行一些判断,并打印相应信息。

static_assert(sizeof(int) == 4, "int must be 4 bytes"); // 检查 int 类型是否为 4 字节template <typename T>
void process(T value) {static_assert(std::is_integral<T>::value, "T must be an integral type"); // 检查模板类型是否为整数类型
}

11.2. 静态分析

VS自带的静态分析,功能非常强大,能够发现很多隐藏的问题。开启静态分析之后,会在编译期间进行静态分析代码,所以会加大编译时间。建议定期开启静态分析检查代码,并修复相关问题。

另外还可以选择相应的静态分析规则:

12. 性能调试

VS提供了性能度量工具(Performance Profiler),帮助开发者优化代码和提高应用程序性能。Profiler的主要功能是诊断内存、CPU 使用率。Debug下的性能分析,因为有很多调试及优化的影响,所以很不准确,建议是在Release版本下进行性能调试分析。

通过Debug->Performance Profiler。C/C++更多用来分析CPU和Memory。

点击Start之后,目标程序开始执行,并开始监控性能,并通过Take Snapshot给当前进程拍摄快照。

12.1. 内存分析

通过Stop Collection或等进程结束,会显示如下信息。每个快照会保存详细的进程堆栈信息。

点击上面的内存分配次数、分配次数增量等数据,可以获取详细信息:

双击相应对象分配行,可以得到详细的对象信息包括调用堆栈信息,通过调用栈可以查看相应的代码:

12.2. CPU分析

内存分类统计:

内存分线程统计:

双击函数名,可以详细函数占比分析:

12.3. 性能提示

调试器在断点或单步执行操作中停止执行时,中断与上一个断点之间经过的时间会显示为在编辑器窗口中的提示。

更多信息见:在 Visual Studio 中度量性能 - Visual Studio (Windows) | Microsoft Learn

协同调试

VS提供了多人协作进行调试的功能,使用非常简单。

  1. 登录VS帐号。

  2. 点击如下图中红圈的图标,启用协作会话。

  1. 协作会话启动完成后,会显示如下信息。默认已经将协作邀请链接进行了拷贝。如果协作方只需要查看代码,不需要调试,可以点击Make read-only。

  1. 将协作邀请链接发给协作方并打开,弹出如下窗口。

  1. 打开VS Code,主持人开始调试,协作方也可以通过VS Code查看调试信息。

  1. 通过VS的File->Join Live Share Session来加入协作调试。

  2. 还可以进行协作的管理,以及协作时聊天。

14. 调试技巧

14.1. 小技巧

  • 使用快捷键,另外还可以自定义快捷键。

  • 固定数据提示信息

  • 格式化内存

调试器也能在 Watch 窗口中显示格式化的内存值,高达 64 个字节。你能用下面的说明符在表达式(变量或内存地址)后来格式化数据。

  • mb / m - BYTE

  • mw - WORD

  • md - DWORD

  • mq – 8BYTE

  • ma – 16BYTE

14.2. 管理员权限调试

通过Linker->Manifest File->UAC Execution Level->requireAdministrator,启用管理员权限,然后启用调试,则被调试的进程也将获取管理员权限。

14.3. 生成调用栈信息

void printStackTrace() 
{HANDLE process = GetCurrentProcess();SymInitialize(process, nullptr, TRUE);void* stack[100];WORD frames = CaptureStackBackTrace(0, 100, stack, nullptr);SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char));symbol->MaxNameLen = 255;symbol->SizeOfStruct = sizeof(SYMBOL_INFO);for (WORD i = 0; i < frames; ++i) {SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);printf("[%d] %s\n", i, symbol->Name);}free(symbol);
}

14.4. 内存耗尽

Windows下的32位应用程序,只能申请2GB内存。所以在申请过的总内存过大时,可能超过2GB,导致程序异常。可以使用下面代码提示总内存过大的提示。

void NoMoreMemory()
{LPVOID lpMsgBuf;if (!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,0x00000008, // Memory error	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language(LPTSTR) &lpMsgBuf,0,NULL )){return;}// Display the string.MessageBox( NULL, (LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );abort();
}// Add to this function to the entry of EXE/DLL.
set_new_handler(NoMoreMemory);

14.5. 未初始化异常

14.5.1. Debug

VS在Debug下为了方便用户调试,编译器会强制将未初始化的变量强制赋值指定值做标记。

栈变量强制赋值0xCCCCCCCC,堆内存强制赋值为0xCDCDCDCD。

14.5.2. Release

在VS下,C/C++中的变量编译器不会对变量进行初始化。栈变量和堆内存都是随机的。养成变量初始化的习惯是提升代码质量的好习惯。

14.6. 调试运行时库代码

VS运行时库,有一些提供了代码,有一些没有提供。如CString的GetLength()函数。VS2012及之前的版本默认不会进入库函数,VS2015及之后版本默认在使用Step Into时会进入库函数。如果无法进入库函数,可以进入汇编调试,然后再Step Into就可以进入库函数了。

14.7. Debug和Release的差异

  1. 编译优化:

    • Debug 模式下,编译器不会进行任何优化,以便于调试和错误定位。

    • Release 模式下,编译器会进行各种优化,以提高程序的性能和执行效率。

  2. 调试信息:

    • Debug 模式下,编译器会生成完整的调试信息,包括变量名、行号等,方便进行调试。

    • Release 模式下,编译器会尽量减少调试信息的生成,以减小程序的体积。

  3. 运行时检查:

    • Debug 模式下,编译器会添加额外的运行时检查,如数组越界检查、内存泄漏检查等,以帮助发现程序中的错误。

    • Release 模式下,这些运行时检查通常会被禁用,以提高程序的执行速度。

  4. 断言和异常处理:

    • Debug 模式下,程序会更加严格地检查各种断言和异常,以帮助开发者发现问题。

    • Release 模式下,这些检查通常会被禁用或简化,以提高程序的稳定性和性能。

  5. 编译器定义宏:

    • Debug 模式下,编译器会定义 _DEBUG 宏,用于在代码中进行条件编译。

    • Release 模式下,编译器会定义 NDEBUG 宏,用于在代码中进行条件编译。

  6. 编译器优化标志:

    • Debug 模式下,编译器通常会使用 /Od 标志禁用优化。

    • Release 模式下,编译器通常会使用 /O2 标志启用最高级别的优化。

  7. 链接器优化:

    • Debug 模式下,链接器通常不会进行任何优化。

    • Release 模式下,链接器会进行各种优化,如去除未使用的函数和数据等。

  8. 运行时库:

    • Debug 模式下,程序会链接到 Debug 版本的运行时库,提供更多的错误检查和调试支持。

    • Release 模式下,程序会链接到 Release 版本的运行时库,以提高性能和减小程序体积。

14.8. 构建事件

有时需要在编译前后附加一些操作来简单调试,就可以使用编译事件配置,选择相应的构建事件然后配置命令行来执行需要附加的操作。

14.9. 日志

日志是调试工具的重要手段,除了使用Trace和OutputDebugString之外,还可以使用自定义的日志函数。

14.10. 调试窗口

VS自带的Spy++可以用来查看窗口信息,还可以用来监控窗口消息。

14.11. 查看DLL接口

dumpbin是VS自带的命令行工具,可以用来查看DLL的接口函数。通过Tools->Command Line来使用。

这是一个命令行工具,可以用于查看 DLL 文件的结构和内容。常用命令:

  • dumpbin /exports <DLL_FILE_PATH>: 查看 DLL 的导出函数

  • dumpbin /dependents <DLL_FILE_PATH>: 查看 DLL 的依赖项

  • dumpbin /headers <DLL_FILE_PATH>: 查看 DLL 的头部信息

15. 总结

调试是手段,不是目的,不能为了调试而调试。目的是更高效地开发,为此,减少问题,减少调试才是最重要的。

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

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

相关文章

JDK的安装和配置

这里写自定义目录标题 1.Java 开发工具包在上方已关联资源下载使用2.JAVA_HOME3.CLASSPATH4.PATH5.包内含有visualvm 1.Java 开发工具包在上方已关联资源下载使用 2.JAVA_HOME JAVA_HOME C:\Program Files\Java\jdk1.8.0_1313.CLASSPATH CLASSPATH .;%JAVA_HOME%\lib\dt.jar…

5月计算机各省报名时间汇总报名流程

&#x1f4e3;5月有5省可进行计算机报名 天津&#xff1a;5月6日-5月10日 福建&#xff1a;5月6日9:00-5月12日17:00 广西&#xff1a;5月6日9:00-5月12日23:55 重庆&#xff1a;5月6日9:00-5月12日24:00 西藏&#xff1a;预计5月6日-12日 &#x1f50d;计算机等级考试报…

花粉过敏人群或超2亿?约克VRF中央空调助你健康鲜呼吸

“一朝春雨落,十里桃花开”,暖春、微风、阳光、花香……充满着生机的春天让人心情愉悦,然而对于易过敏人群来说却是“苦不堪言”,经常出现眼圈发红、发痒、睁不开,每天都在“流泪”中度过,同时伴随着咳嗽、打喷嚏、流鼻涕、鼻塞等症状,皮肤也可能会出现红疹、瘙痒等症状。 如何…

在Linux安装mysql

由于大多数开发&#xff0c;测试活动都是在linux中进行的&#xff0c;所以建议先学linux&#xff0c;可以看看下面这个文章&#xff1a; Linux命令超详细介绍-CSDN博客 1、先去下载mysql的linux安装包&#xff1a;MySQL :: Download MySQL Community Server (Archived Versio…

第十五届蓝桥杯省赛第二场C/C++B组G题【最强小队】题解

20pts 枚举所有可能的左端点、右端点&#xff0c;时间复杂度 O ( n 2 ) O(n^2) O(n2)。 对于每个区间进行遍历检测&#xff0c;时间复杂度 O ( n 3 ) O(n^3) O(n3)。 100pts 由于数据范围为 1 0 5 10^5 105&#xff0c;所以肯定只能进行一次枚举。 我们尝试枚举右端点&…

中小型企业网络实战topo

1、设备命名&#xff0c;务必按照规范进行命名规划&#xff1b; 2、子网划分&#xff0c;申请到了公网地址段&#xff0c;201.1.1.0/24&#xff0c;根据公司的实际情况&#xff0c;合理规划拓扑需要的公网地址&#xff0c; 做到合理规划不浪费&#xff1b; 3、子网划分&a…

ZooKeeper设置监听器

ZooKeeper设置监听器&#xff0c;通过getData()/getChildern()/xists()方法。 步骤&#xff1a; 1.创建监听器&#xff1a;创建一个实现Watcher接口的类&#xff0c;实现process()方法。这个方法会在ZooKeeper向客户端发送一个Watcher事件通知的时候被调用。 2.注册监听器&…

k-均值聚类

K均值聚类&#xff08;K-means clustering&#xff09;是一种常用的无监督学习方法&#xff0c;用于将一组数据点划分为K个簇&#xff08;cluster&#xff09;。 它的目标是将相似的数据点归到同一个簇中&#xff0c;同时使得不同簇之间的数据点尽可能不相似。K均值聚类算法的…

数据库MySQL的初级基础操作

文章目录 1. 介绍2. 数据库相关概念3. 启动4. 数据模型5. SQL6. DDL数据库DDL-表操作DDL-表操作-数据类型DDL-表操作-修改DDL-表操作-删除 7. 图形化界面工具DataGrip8. DML(数据操作语言)DML-添加数据DML-修改数据 9. DQL&#xff08;数据查询语言&#xff09;基本查询条件查询…

第十五届蓝桥杯省赛第二场C/C++B组F题【狡兔k窟】题解(AC)

题意分析 有一个 n n n 个点&#xff0c; n − 1 n-1 n−1 条边的无向图&#xff0c;边权均为 1 1 1。 每个点隶属于一个集合&#xff0c;同一个集合的点可以互相传送。 给定 m m m 个询问&#xff0c;求 x , y x, y x,y 的最短距离。 最短路解法 步骤&#xff1a; 建…

N5245B PNA-X 微波网络分析仪

N5245B PNA-X 微波网络分析仪 " 900 Hz/10 MHz 至 50 GHz " N5245B PNA-X 微波网络分析仪&#xff0c;900 Hz/10 MHz 至 50 GHz&#xff0c;2 端口和 4 端口&#xff0c;多达三个信号源。 特点 实现卓越性能 这款 PNA-X 分析仪不仅仅是一款矢量网络分析仪&a…

《QT实用小工具·四十》显示帧率的控件

1、概述 源码放在文章末尾 该项目实现了可以显示帧率的控件&#xff0c;项目demo演示如下所示&#xff1a; 、 项目部分代码如下所示&#xff1a; #ifndef FPSITEM_H #define FPSITEM_H#include <QQuickItem>class FpsItem : public QQuickItem {Q_OBJECTQ_PROPERTY(i…

ubuntu20 解决网线不能联网 RTL8111/8168/8411

这种问题一般是驱动没有正确安装。 ----RTL8111/8168/8411是一块比较坑的网卡。 1、 查看网卡信息 lspci |grep Ethernet2、 对于高版本的Ubuntu&#xff0c;能直接使用命令安装驱动。下面的r8168-dkms需根据网卡信息修改&#xff0c;上面的网卡信息还有8111&#xff0c;但逐个…

CUDA的应用场景

CUDA的应用场景随着技术的发展不断扩展&#xff0c;其核心优势在于能够显著提高并行计算任务的处理速度&#xff0c;这对于任何需要处理大量数据和执行复杂计算的领域都是极其有价值的。CUDA开发的应用场景非常广泛&#xff0c;主要得益于其强大的并行计算能力&#xff0c;以下…

buuctf——[CISCN2019 华北赛区 Day2 Web1]Hack World

buuctf——[CISCN2019 华北赛区 Day2 Web1]Hack World 1.根据提示&#xff0c;说明flag在表里 2.那就猜测存在sql注入&#xff0c;反手测试一波id1 3.尝试使用1--进行注释 4.直接丢进salmap里吧&#xff0c;不出意外多半是跑不出来 5.直接放入fuzz里进行测试 6.发现当我…

iOS - 多线程-GCD

文章目录 iOS - 多线程-GCD1. 常见多线程方案2. GCD2.1 GCD的常见函数GCD中有2个用来执行任务的函数 2.2 GCD的队列2.2.1 GCD的队列可以分为2大类型 2.3 容易混淆的术语2.4.1 有4个术语比较容易混淆&#xff1a;同步、异步、并发、串行 2.4 各种队列的执行效果 3. 死锁3.1 死锁…

Composer初次接触

php一直都是简单处理一下单片机的后台服务&#xff0c;没什么深入研究 今天安装一个 php composer.phar require qiniu/php-sdkComposer完全不懂&#xff0c;照着一试&#xff0c;就报错了 - topthink/think-installer v1.0.12 requires composer-plugin-api ^1.0 -> found…

ThreeJs模拟工厂生产过程三

上节课绘制了车间模型&#xff0c;但是车间里只有一条产线&#xff0c;这节把产线多铺设几条&#xff0c;放满整个车间&#xff0c;但是随着放满车间吗&#xff0c;也就意味着要创建更多的模型&#xff0c;而更多的模型会导致浏览器卡顿&#xff0c;所以这个节讲如何做模型合并…

Python | Leetcode Python题解之第48题旋转图像

题目&#xff1a; 题解&#xff1a; class Solution:def rotate(self, matrix: List[List[int]]) -> None:n len(matrix)# 水平翻转for i in range(n // 2):for j in range(n):matrix[i][j], matrix[n - i - 1][j] matrix[n - i - 1][j], matrix[i][j]# 主对角线翻转for …

Python400集 视频教程,手把手带你零基础手写神经网络!!

嗨喽&#xff0c;大家好&#xff0c;今天又要给大家整一波福利了&#xff01; 学习编程&#xff0c;最忌讳就是今天一个教程&#xff0c;明天一个教程&#xff0c;频繁更换教程&#xff0c;增加自己的学习成本&#xff0c;对于新手小白会是一件严重打击自信心的事情。所以今天…