首页 > 其他分享 >Visual Studio高效调试手段与调试技巧总结

Visual Studio高效调试手段与调试技巧总结

时间:2024-06-11 18:32:56浏览次数:12  
标签:代码 C++ Visual VS Studio 内存 断点 调试

目录

1、对0xCCCCCCCC、0xCDCDCDCD、0xFEEEFEEE和0xDDDDDDDD等常见异常值的辨识度

2、在Debug下遇到报错弹框,点击重试,查看函数调用堆栈

3、调试时程序和调试器都发生了闪退,可以尝试到Output窗口中找线索

4、调用OutputDebugString接口,将打印日志输出到调试器输出窗口中

5、调用被废弃的API函数IsBadReadPtr和IsBadWritePtr,可能会导致VS调试时产生异常 

6、VS自带的异常中断选项

7、条件断点与人为构造的临时过滤条件

8、巧用数据断点

9、将VS附加到目标上调试

10、使用VS和IDA查看汇编代码

11、最后


c1f3a6b4dae7443eb59f400638d659d0.png

       用了多年的Visual Studio,很多人是不是还没完全掌握其有效的调试方法和技巧?是否还是无法快速定位问题?本文将根据多年使用Visual Studio的经验,带着大伙逐一认识和掌握Visual Studio多种实用的调试方法和技巧,帮助大家去高效地解决开发过程中遇到的多种难题。

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

1、对0xCCCCCCCC、0xCDCDCDCD、0xFEEEFEEE和0xDDDDDDDD等常见异常值的辨识度

       我们在调试程序的过程中,当遇到0xCCCCCCCC、0xCDCDCDCD和0xFEEEFEEE、0xDDDDDDDD等特殊的异常内存地址或异常值时(如果程序中访问了这些非用户态的内存地址,会产生内存访问违例),我们应立即察觉到程序可能出问题了。常见的异常地址说明如下:

0xcccccccc : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory.

0xcdcdcdcd : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory.

0xfeeefeee : Used by Microsoft's HeapFree() to mark freed heap memory.

0xdddddddd:Used by MicroQuill's SmartHeap and Microsoft's C/C++ debug free() function to mark freed heap memory.

0xabababab : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory.

0xabadcafe : A startup to this value to initialize all free memory to catch errant pointers.

0xbaadf00d : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory.

0xbadcab1e : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger.

0xbeefcace : Used by Microsoft .NET as a magic number in resource files.

       这些值是微软调试器故意在某些场景下设置的特殊值,便于程序员快速地察觉到可能存在的问题。其中,0xCCCCCCC是微软调试器在Debug下填充到未初始化的栈内存中的值,当字符串看就是 “烫烫烫烫……”;0xCDCDCDCD是微软调试器在Debug下填充到未初始化的堆内存中的值,当字符串看就是 “屯屯屯屯……”;0xFEEEFEEE是填充到已经释放的堆内存中的值。

       所以遇到值为0xCCCCCCC或者0xCDCDCDCD的变量时,可能是这些变量没有初始化就被访问或使用了,会触发内存访问违例,所以大家平时要养成初始化变量的习惯。当遇到值为0xFEEEFEEE的变量时,有可能是该变量指向的内存已经被释放了,不能再使用了,再使用也会触发内存访问违例。

       对于0xdddddddd,是Debug下用来标记堆上已经释放掉的内存,即已经释放的堆内存会被填充成0xdddddddd。 0xfeeefeee也是Debug下用来填充已经释放的堆内存,但0xdddddddd和0xfeeefeee的场景应该是有区别的,具体区别不太清楚,仅从上面的说明文字中没法区分。

之前在项目问题中看到的基本都是0xfeeefeee,没见到过0xdddddddd,但前段时间在Debug下调试代码时就遇到了0xdddddddd:

代码中访问了已经释放的内存,内存中都被置为0xdddddddd,这还是第一次遇到0xdddddddd异常值!正是通过0xdddddddd的说明,得知这个0xdddddddd是用来填充已经释放的堆内存,以这个为线索,快速地定位了问题!

       关于这些常见异常地址的项目问题实战排查案例,可以查看我之前写的几篇文章:

排查软件启动时访问了0xcdcdcdcd内存地址导致内存访问违例的崩溃icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125266735排查软件关闭时访问了0xfeeefeee内存地址导致内存访问违例的崩溃icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125267046访问0xdddddddd内存地址引发软件崩溃的问题排查icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/132631020


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

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

C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

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

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

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

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战经验为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对C++相关知识点进行详细地展开与剖析!专栏涉及了C/C++开发领域多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

VC++常用功能开发汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585

专栏将10多年C++开发实践中常用的功能,以高质量的代码展现出来,并对相关功能的实现细节进行了详细的说明。这些常用的代码,其质量与稳定性是有保证的,可以直接拿过去使用,可以有效地解决C++软件开发过程中遇到的问题。


2、在Debug下遇到报错弹框,点击重试,查看函数调用堆栈

      在Debug下调试代码时,会时常遇到这样的报错弹框:

f833f660329545b78b6e9e0742fba8ff.png

其实很简单,此时只要点击重试按钮,调试器就会中断下来,然后打开VS的调用堆栈(call stack)窗口去查看此时的函数调用堆栈,通过函数调用堆栈就能大概看出是执行了什么操作引发了异常。

       但有时光看函数调用堆栈,可能并不能看出问题所在,我们还可以尝试去看Output输出窗口中输出的信息,编译器和程序可能会将一些调试打印信息输出到Output窗口中,从打印信息中可能能找到线索。比如我们在使用duilib界面框架编写窗口的xml文件时,写了非法的xml节点:

838b8393b5ba4b6da5cdd934505107db.png

从上图打印的信息可以看出,是duilib库在解析窗口的xml内容时产生了异常,duilib将有异常的xml节点附近的xml上下文打印到Output窗口中,通过这个打印我们就能快速地找到xml中出问题的节点了。此问题是问题节点的开始符号“<”和结尾符“/>”不匹配导致的,具体地,是我们在手动编写xml文件时手误写错导致的。

3、调试时程序与调试器都发生了闪退,可以尝试到VS的Output窗口中查看打印找线索

       比如程序发生“stack overflow”线程栈溢出,有可能是函数递归调用触发的,也有可能是函数之间发生死循环调用触发的,也有可能是函数中的case语句分支过多导致的。只要发生了线程栈溢出的异常,程序就会直接闪退,调试器也会直接退出调试状态,此时无法查看异常时的详细信息,查看不到异常时的函数调用堆栈,更查看不到发生异常时相关变量的值。

        不过此时可以尝试到VS的Output窗口中看看,看看能否从打印的信息中找到一些线索。对于线程栈溢出时的闪退,会在Output窗口中输出“Stack overflow”异常提示信息,如下所示:

a5aa329c792a4ed781b92cba2592e827.png

这样我们就知道发生线程栈溢出了。

       那我们如何才能找到发生线程栈溢出时的函数调用堆栈呢?下面就轮到强大的Windows调试器Windbg上场了,可以重新运行程序,然后将Windbg附加到程序的进程上,复现线程栈溢出的问题。一旦问题复现,Windbg会立即检测到该stack overflow的异常,中断下来,在Windbg中输入kn、kv或kp命令,就可以查看此时的函数调用堆栈了。查看到了函数调用堆栈,就知道是什么操作引发的异常了。

线程栈溢出我们已经遇到过多次了,在这方面比较有经验。

       关于如何将Windbg附加到进程上调试(或者用Windbg直接启动程序进行调试),可以查看我的文章:

使用Windbg调试目标进程的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131029795

4、调用OutputDebugString API接口,将打印日志输出到调试器输出窗口中

       我们可以在代码中调用Windows API函数OutputDebugString将打印日志输出到调试器的输出窗口中。VS中自带的TRACE宏,也可以将日志输出到调试窗口中,但TRACE宏只在Debug下才有用,Relase下是无效的。其实TRACE宏内部在Debug下也是调用API函数OutputDebugString的,在Relase下该宏定义为空,TRACE宏的内部实现如下:

#define TRACE                       CONCRT_TRACE

// Enable tracing mechanisms
#if defined(_DEBUG) && defined(CONCRT_TRACING)
# define CONCRT_TRACE(...)  ::Concurrency::details::_ConcRT_Trace(__VA_ARGS__)
#else
# define CONCRT_TRACE(...)  ((void)0)
#endif

// Trace -- Used for tracing and debugging
void _ConcRT_Trace(
    int trace_level,
    const wchar_t * format,
    ...
    )
{
    InitializeUtilityRoutines();

    // Check if tracing is disabled
    if ((g_DesiredTraceLevel & trace_level) == 0) {
        return;
    }

    wchar_t buffer[1024+1];

    va_list args;
    va_start(args, format);
    ConcRT_FillBuffer(buffer, format, args);
    va_end(args);

    buffer[1024] = 0;

    if (g_DebugOutFilePtr != NULL)
    {
        fwprintf(g_DebugOutFilePtr, buffer);
        if (g_CommitFrequency > 0 && (g_TraceCount++ % g_CommitFrequency) == 0)
            fflush(g_DebugOutFilePtr);
    }
    else
    {
        OutputDebugStringW(buffer);
    }
}

       系统API函数OutputDebugString无论是在Debug下,还是在Release下都会生效,会将打印日志输出到正在调试的调试器输出窗口中。如果我们在使用VS调试,打印信息会输出到VS的输出窗口中;如果我们在使用调试器Windbg附加到进程上调试,打印信息则会输出到Windbg的输出窗口中

       那OutputDebugString是如何将打印日志(字符串)输出到调试窗口中的呢?我们可以到ReactOS操作系统的开源代码中查看OutputDebugString的内部实现:(和Windows接口的内部实现基本一致的,我们经常以ReactOS开源系统的接口实现去猜测Windows接口的实现)

VOID WINAPI OutputDebugStringA(IN LPCSTR _OutputString)
{
    _SEH2_TRY
    {
        ULONG_PTR a_nArgs[2];

        a_nArgs[0] = (ULONG_PTR)(strlen(_OutputString) + 1);
        a_nArgs[1] = (ULONG_PTR)_OutputString;

        /* send the string to the user-mode debugger */
        RaiseException(DBG_PRINTEXCEPTION_C, 0, 2, a_nArgs);
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        // 此处代码省略
        // ......
    }
}

从上述代码可以看出,OutputDebugString内部调用了RaiseException接口产生了一个DBG_PRINTEXCEPTION_C异常(会产生了一个标准的EXCEPTION_RECORD异常结构),该异常会被发到内核的异常处理模块,然后由内核异常处理模块将该异常分发给用户态的调试器,调试器最终将打印日志显示到调试器的输出窗口中。

       比如我们使用的WebRTC开源库会将运行日志输出到调试器的输出窗口中,比如我们在使用Windbg附加到进程中调试时,在Windbg的输出窗口中可以看到WebRTC库输出的运行日志。后来查看WebRTC库的源代码得知,WebRTC库内部也是调用OutputDebugString将打印日志输出到调试器的输出窗口中的,代码如下:

ef2a07f00ad24d7d862472ab59e032dd.png

       有人可能会说,他们有完善的日志管理系统,不需要使用OutputDebugString API函数了。我们这个地方主要介绍这种输出日志的手段,大家可以根据自己的需要去选择。

5、调用被废弃的API函数IsBadReadPtr和IsBadWritePtr,可能会导致VS调试时产生异常 

       有人经常会问,有没有系统API能判断当前内存地址是否可读可写,这样我们在读写内存之前可以使用这样的API函数去判断一下。Windows之前是提供过IsBadReadPtr和IsBadWritePtr这样的API接口,但这两个API函数现在已经废弃了,不能再使用了,即这两个接口不再起到判断内存是否可读可写的作用了

MSDN上对该函数的说明
Important:This function is obsolete(废弃的) and should not be used. Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. .

       有的第三方老的库可能还调用了这两个接口,在VS调试时可能会触发一个异常,VS中断下来,但该异常不是致命的,可以直接跳过去(按下F5即可跳过去),程序可以继续详细运行。这种异常在使用VS或Windbg调试时都会引发中断,我们在日常工作中都遇到过。VS中只需要取消勾选“遇到此异常不再中断”,下次就不会再弹出了

ef6e7ad2359d456f9a97585a2a94a830.png

      如果在使用Windbg进行动态调试,只需要输入并执行g命令即可跳过去:(如果代码中多次调用了IsBadReadPtr或IsBadWritePtr,可能要go多次,即多次跳过)

19457cf327ab4642b0f13fbf5935790d.png

      关于调用IsBadWritePtr和IsBadReadPtr引发问题的案例,可以查看我的文章:

使用Windbg排查C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/129892952

6、VS自带的异常中断选项

       VS中可以去指定想要中断的异常类型或者特殊异常,当发生这些异常时调试器就会中断下来,此时就可以去查看函数调用堆栈,去分析是什么原因触发的异常了。点击VS菜单栏中的Debug->Exceptions,弹出异常选项勾选对话框:

fb2a5d03190b4ac291faa8101f36b1ac.png

VS默认只勾选了一部分选项,你可以勾选你想用到的选项。

       比如我们可以勾选c000008c Array bounds exceeded和c00000fd Stack overflow,这样VS在捕捉到这些异常时VS就会中断下来。上面讲到程序发生stack overflow异常时,程序会闪退,调试器也会直接退出调试状态,如果此处勾选了“c00000fd Stack overflow”选项,估计调试器会立即中断下来,这样我们就可以看到函数调用堆栈了,这个大家可以尝试一下。

7、条件断点与人为构造的临时过滤条件

       VS中可以给断点设置过滤条件,满足条件后断点就会中断下来。添加条件断点的方法是,先添加一般断点,然后右键点击该断点,给断点设置条件,如下所示:

8e597cc7234848b4af06726fadcd3ed4.png

 一般我们主要使用“条件”、“命中次数”和“筛选器”三种类型。可以设置命中断点的表达式条件,也可以设置断点的命中次数(包含大于、等于和小于),也可以给断点设置筛选器。

       设置筛选器的界面如下:

e4185bef44fc4b69973bb13eba3874ec.png

在设置筛选条件时,可以设置线程id,这在多线程调试时比较有用。当然要事先打断点,将目标线程的id记录下来,然后再来设置过滤线程的条件。

       但条件断点中设置条件表达式比较苛刻,只能设置简单的表达式,很多复杂点的表达式都不支持,设置后会提示不能设置这样的条件。个人觉得还是人为添加临时的if过滤条件代码最灵活(断点设置在if语句的body体中),我们平时经常使用这种方法,比如我们想在duilib库的CEditUI编辑框控件的DoEvent接口中添加断点进行调试,这个控件很多窗口都会使用,但我们只想调试某个窗口中的CEditUI控件对象,如果在DoEvent接口中直接打断点,会中断很多次,所以我们在该接口中人为添加if过滤条件的代码,通过控件名称(每个窗口中的控件名称是不同的)将目标对象过滤出来:

5e01cc0f38cd4d848adc22318d9f505f.png

然后将断点设置在if语句的body中。这种添加临时if过滤条件代码的方式很灵活,可以设置各种复杂的过滤条件。我们在日常工作中主要还是使用临时添加if过滤条件的方式。

8、巧用数据断点

       我们有时会遇到变量值无故被篡改,导致程序逻辑出现异常或产生崩溃,这类问题我们遇到好几次了。在最初排查问题时,搜索了操作变量的所有代码,仔细排查了都没问题,并添加了日志打印,运行程序后打印出来的日志显示也没问题,但变量就是被无缘无故地被篡改了!

       这种情况一般都是内存越界导致的,内存越界有全局内存越界、栈内存越界和堆内存越界,直接排查代码是很难找到问题的。遇到这种情况,应该第一时间想到数据断点,第一时间请数据断点上场。

       设置数据断点其实就是监控目标变量的内存,一旦内存被修改,就会命中该数据断点,调试器就会中断下来设置数据断点是有技巧的,被监控的目标变量需要在被分配内存后才能被监控,一般在类的构造函数中先设置一般断点,命中断点后,目标监控变量就分配了内存,就可以通过表达式“&变量名”去设置数据断点了:(可以设置监控的内存长度)

0fbe8c72bf0d411f8b96382298dc4295.png

一旦被监控的内存被修改,就会命中对应的数据断点,此时去查看函数调用堆栈就可以看到是什么代码篡改了目标变量的内存了。

       这个地方需要留意一下,正常的赋值也是修改内存中的内容,也会命中数据断点,所以要将正常的赋值和内存越界篡改内存的情况区别开来。

       关于使用数据断点的实战分析案例,可以查看我的文章:

巧用Visual Studio中的数据断点去排查C++内存越界问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125626617

9、将VS附加到目标上调试

       很多时候直接调试源代码是最直接最有效的,除了使用VS直接调试代码之外,还支持将VS附加到目标进程上调试。这特别适用底层库(比如网络库、协议库、组件库等)的调试。

       一般情况下,当程序发生崩溃时,我们会取来程序异常捕获模块捕获到的保存异常上下文信息的dump文件,先用Windbg对异常进行分析,在排查不出问题时,如果问题好复现,我们会建议发生崩溃的dll模块的维护组尝试去使用VS手动附加调试一下,让他们去看看到底是什么问题。

       附加调试之前,先将编译出来的dll库拷贝到exe程序的目录中,然后重新启动程序。再将打开待调试库代码的VS附加到目标进程上调试。如果要调试release版本(有的问题可能在debug下没问题,只在release下有问题,所以需要进行release版本的调试),则需要事先在工程属性中将优化关闭掉。

       VS附加调试的入口:点击VS菜单栏中的“调试->附件到进程”,打开附加到进程的窗口,如下:

4bf9560555a941b5bb559d87cdcc5092.png

然后选择要附加到的目标进程,点击确定就可以了。

有人可能会问,直接将编译出来的dll库拷贝到目标exe程序的路径中,为啥能调试呢?其实本质上,函数变量符号及调试信息都是放置在pdb文件中的,拷贝过去的库文件中会默认写入其使用的pdb文件的绝对路径,不管你将dll库文件拷贝到本机的哪个位置,都能根据绝对路径找到pdb文件,都能加载到库的调试信息,所以都能进行调试的。如果手动将对应的pdb文件删除掉,就没法进行调试的。

       这个附加调试一般在目标进程启动后去附加,但有时我们可能需要调试程序启动时的初始化代码,但等程序启动起来后,初始化的代码都执行完了,都没有机会调试了。这里有个技巧,可以在被调试进程的main函数中添加一个messagebox,先将目标进程阻塞住,等待VS附加到进程中,然后再点击messagebox中的OK按钮继续运行程序,这样就能调试初始化的代码了。

10、使用VS和IDA查看汇编代码

       一般情况下,在分析软件异常时,我们会用Windbg打开包含异常信息的dump文件或者将Windbg附加到目标进程上去调试。关于如何使用Windbg,可以参见之前写的这篇文章:

Windbg调试工具使用详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/120631007

       软件是崩溃在某一条汇编指令上,Windbg中可以看到这条崩溃的汇编指令,但有时很难通过C++代码看出为啥会导致崩溃,这时就需要去查看对应模块的二进制文件(dll或exe)的汇编代码的上下文,看看到底为啥会导致那句汇编代码崩溃了。

       我们平时一般会使用反汇编工具IDA Pro去打开二进制文件,去查看二进制文件对应的汇编代码。关于如何使用IDA工具,可以参见之前写的这篇文章:

IDA反汇编工具使用详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/120635120

       其实我们也可以在VS中查看C++代码对应的汇编代码,先在要查看汇编代码的C++代码处添加断点,当命中断点时,点击右键,在弹出的右键菜单中点击“转到反汇编”菜单项:

24604383e13e4d7ab795f923dabcdd94.png

即可看到C++代码对应的汇编代码了,这对学习C++语句的汇编代码也是很有好处的。切换到汇编代码页面后,我们也可以直接调试汇编代码

       在查看汇编代码时,可以将C++代码与汇编代码一起对照看,从而搞清楚很多场景下的汇编代码是怎么编写的,这对我们走读汇编代码的上下文很有帮助。当我们遇到读不懂的汇编代码时,我们会在VS中写一些C++测试代码,然后这些C++代码的汇编代码是什么样子的,通过类比就能搞清楚了。

       对于分析C++软件异常需要掌握哪些基本的汇编知识,可以查看我之前写的一篇文章:

分析C++软件异常需要掌握的汇编知识汇总(实战经验分享)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124758670

11、最后

       作为使用VS开发调试的开发人员,很有必要去掌握上述调试技巧的。在掌握这些调试手段与技巧之后,能让我们在排查问题时更加的高效。大家如果有什么好的调试方法和技巧,可以在评论区一起讨论。

标签:代码,C++,Visual,VS,Studio,内存,断点,调试
From: https://blog.csdn.net/chenlycly/article/details/139596858

相关文章

  • 【文档+源码+调试讲解】体育馆管理系统的设计与实现
    摘要随着信息互联网购物的飞速发展,一般有能力的机构管理系统。本文介绍了镇赉县一中体育馆管理系统的开发全过程。通过分析企业对于镇赉县一中体育馆管理系统的需求,创建了一个计算机管理镇赉县一中体育馆管理系统的方案。文章介绍了镇赉县一中体育馆管理系统的系统分析部分,包......
  • Android studio(创建、监听器intent菜单)
    创建报错connectrunout可以查看这篇文章1.自动创建  2.设置输出日志信息logt+tab键之后会为当前的类自动生成一个TAG常量 关于日志过滤器 这时候在只有Log.v里面的消息,Log.d、i、w、e都没有出现。当输入MainActivity的时候过滤到与其相关的 3.手动创建选......
  • 【译】Visual Studio 17.10 发布了新版扩展管理器
    我们将更新的扩展管理器带给所有用户!在过去的一年里,我们已经将更新后的扩展管理器作为可选的预览功能提供,并一直期待您的反馈。基于您令人难以置信的反馈,我们现在准备从VisualStudio17.10开始提供新的扩展管理器作为默认预览功能。我们已将基本功能简化为现代风格UI,以......
  • Android studio实现图标方式展示信息(折线图等)时com.github.mikephil.charting.charts.
    参考连接——https://blog.csdn.net/m0_37919094/article/details/122416408 去https://gitcode.com/PhilJay/MPAndroidChart/overview?utm_source=csdn_github_accelerator&isLogin=1下载MPAndroidChart的zip包,解压 在Androidstudio中操作file——》new——》importm......
  • 探索JavaScript调试技巧与工具
    ......
  • 【驱动】Linux内核调试之使用模块参数
    环境:处理器架构:arm64内核源码:linux-6.6.29ubuntu版本:20.04.1代码阅读工具:vim+ctags+cscope本文主要介绍内核开发中常用的模块传参手段,通过模块参数传递可以通过用户态来获取内核的一些信息,也可以通过用户态写入一些值来控制内核相关行为。一般内核开发者很喜欢使用模块传参......
  • Android studio 连接sqlist数据库,账号密码错误仍能登录的原因
    昨天在写Androidstudio的大作业,写到连接sqlist数据库实现登录的时候明明账号密码都不正确,但是用户却可以登录,我原先以为是我sql语句写错了,将sql语句从Cursorcursor=db.rawQuery("select*fromuserwherenamelike?andpasswordlike?",newString[]{name,password});改......
  • SQL Server Management Studio (SSMS) 20.1 - 微软数据库管理工具
    SQLServerManagementStudio(SSMS)20.1-微软数据库管理工具请访问原文链接:https://sysin.org/blog/ssms/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org笔者注:SQLServer2014及之前版本内置SQLServerManagementStudio(SSMS),SQLServer2016及以后版本......
  • FL Studio for Mac 21.2.3.3586官方中文破解版及FL注册解锁秘钥
    Hey小仙女们!今天小助手来跟你们分享一个超级激动人心的消息哦!你们有没有听说过FLStudio21破解版?这可是一款让你的音乐创作更加轻松、时尚和精彩的软件呢!FLStudioforMac21.2.3.3586官方中文破解版重磅发布纯正简体中文支持,更快捷的音频剪辑及素材管理器,多样主题随心......
  • Intellij插件之调试停止生命周期
    Intellij插件之调试停止生命周期目录Intellij插件之调试停止生命周期调试会话的创建调试停止调试会话各个监听器停止顺序调试会话的创建调试会话的创建由XDebuggerManager.startSessionAndShowTab接口创建,返回一个类型为XDebugSession的实例。它会在Debug窗口创建一个......