Visual Studio高级调试技巧

VS2022调试vector无法显示详细信息 为了显示vector大小以及详细的元素,需要编写natvis文件。 阅读详情

转自:Visual Studio高级调试技巧 - 可可西 - 博客园

1. 设置软件断点,运行到目标位置启动调试器

方法①:使用汇编指令(注:x64 c++不支持嵌入汇编)

_asm int 3

方法②:编译器提供的方法

__debugbreak();

方法③:使用windows API

DebugBreak();

WerFault.exe进程(Windows Error Reporting)弹出ConsoleTest.exe已停止工作:

要想出现“调试程序”选项,需要将Windows Error Reporting注册表信息设置成如下图所示(注:特别是红框的内容)

如果在注册表AeDebug的Debugger项配置了VSJitDebugger路径,且VSJitDebugger安装正常

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug  // 注:64位系统上的32位程序使用该注册表项

点击“调试程序”选项就会弹出Visual Studio实时调试器对话框,选择对应的调试器后,点击“是”就可以启动调试器并中断到软件断点位置了

需要注意的是,软件断点也是一种异常,一旦被处理,就不会传到WerFault.exe进程上,那么这种方法也就失效了!

下面两种情况软件断点异常会被处理:

① 被SEH异常捕获并处理

② 被自定义的全局异常函数处理

注:可以将上面两种情况中的EXCEPTION_EXECUTE_HANDLER修改为EXCEPTION_CONTINUE_SEARCH来指明异常未得到处理

2. 修改变量(注:在悬停出来小面板、Locals窗口、Autos窗口、Watch窗口、或Quick Watch窗口中进行修改;也可以在Immediate窗口中执行:bFlag=false)

3. 格式化变量

注:d,i:有符号的十进制数
      u:无符号的十进制数
      o:无符号的八进制数
      x:十六进制数(字母小写)
      X:十六进制数(字母大写)

更多详见:Format specifiers for C++ in the Visual Studio debugger

4. 修改内存(注:在内存窗口中,将光标定位到要修改的地方,直接按0-9输入十六进制;要输入a-f则需通过右键菜单中的“Edit Value”进行输入)

5. 格式化显示内存

6. 设置下一个运行位置(注:直接拖动黄色箭头到想要的运行位置)

示例中:传入的bFlag为true,代码开始运行到断点处(43行),然后重新把黄色箭头拖回39行,此时bFlag的值为false,按F10会进入else分支

注:(1)跳过中间所有指令。意味着:printf("True\n")及CTest的析构函数均不会被执行

      (2)当拖动箭头到一个新的函数中时,vs会将原来的函数从栈中弹出,将新函数压入栈顶;

             由于新函数与上层函数没有调用关系,输出类型的参数及返回值很有可能写坏上层函数的栈数据

      (3)该调试技巧为一种事后行为,应谨慎使用,最好是只在函数内局部使用

7. 编辑然后继续运行

(1)不能在64位代码上使用

(2)使用“Program Database for Edit & Continue (/ZI)”生成pdb文件

(3)仅适用于函数内部改变(若要修改函数原型或增加新函数,只能选择重启程序)

8. 变量的一些特殊查看方法

以$和@开头的伪变量:(注:$和@两个符号是一样的,随便用哪个都可以)

$err -- 获取GetLastError()的返回值    注:linux中,系统api的最近错误码可通过errno全局变量来获取

$err,hr -- 获取GetLastError()的返回值并解释返回值的含义

@eax -- 查看eax的值(64位为@rax)

@esp+4 -- 函数的第一个参数地址

$handles -- 查看打开的句柄数

$pid -- 当前进程id

$tid  -- 当前线程id

$vframe  -- 当前栈帧的ebp

$clk  -- 以时钟周期为单位显示时间

$ReturnValue -- 查看函数的返回值

Message,wm --以windows消息的宏形式显示 如:Message为15时,显示为WM_PAINT(注:Message为unsigned int类型)

hResult,hr --hResult为0x80070005时,显示为E_ACCESSDENIED(注:hResult为void*类型)

pArray,10 --从pArray地址起显示后续10个int类型的数据(注:pArray为int*类型)

(pArray+5),3 --从pArray[5]地址起显示后续3个int类型的数据(注:pArray为int*类型)

更多详见:Pseudovariables in the Visual Studio debugger

9. 获取简单类型的函数返回值

注1:不能为inline函数

注2:执行函数的下一条语句时,查看eax或伪变量ReturnValue的值

10. 使用指针类型转换查看某个地址的变量

注:有时候,尽管对象仍然存在,在调试符号越界后,watch窗口中的变量是被禁用的,不能再查看(也不能更新)。

      若知道对象的地址,则可以将地址转换为该对象类型的指针,放在watch窗中来继续观察它。

11. 查看其他模块的全局变量

{,,UE4Editor-Core.dll}GIsEditor   // 当前是否为编辑器

{,,UE4Editor-Core.dll}GIsClient   // 当前是否为客户端

{,,UE4Editor-Core.dll}GFrameCounter  // 当前帧序号 1100

{,,UE4Editor-Core.dll}GFrameNumber // 当前帧序号 1101

{,,UE4Editor-Core.dll}GFrameNumberRenderThread // 当前帧序号 1102

{,,UE4Editor-Core.dll}GPlayInEditorID  // PIE ID(适用于多玩家,也可作为断点条件)

{,,UE4Editor-Engine-Win64-Debug}::GPlayInEditorContextString // PIE窗口名称(适用于多玩家)

注:UE4Editor-Core.dll为全局变量GIsEditor、GIsClient、GFrameCounter所在的模块

还要另外一个方法是:通过看汇编代码,找到全局变量对应的地址,然后在Memory中查看对应的值或在Watch窗口里面将地址转换成对应的类型

12. 查看函数指针地址具体对应哪个函数

注:如果某个地址为函数,通过void*类型转换可看到函数名称 

13. Immediate窗口

① 求类型或对象的大小

? sizeof(int)
4
? sizeof(lua_State)
208
? sizeof(L)
8 

② 输出字符串

? "go out"
"go out"
    [0]: 103 'g'
    [1]: 111 'o'
    [2]: 32 ' '
    [3]: 111 'o'
    [4]: 117 'u'
    [5]: 116 't'
    [6]: 0 '\0'
? "go \nout",sb   // 带上sb,回车符会换行打印
go 
out
    [0]: 103 'g'
    [1]: 111 'o'
    [2]: 32 ' '
    [3]: 10 '\n'
    [4]: 111 'o'
    [5]: 117 'u'
    [6]: 116 't'
    [7]: 0 '\0'

③打印变量

? n
100
? g_rc
{w=0.000000000 h=0.000000000 }
    w: 0.000000000
    h: 0.000000000
? L
0x00000218c5702128 {next=0x0000000000000000 <NULL> tt=8 '\b' marked=0 '\0' ...}
    next: 0x0000000000000000 <NULL>
    tt: 8 '\b'
    marked: 0 '\0'
    nci: 7
    status: 0 '\0'
    top: 0x00000218c570d7a0 {value_={gc=0x00007ff790a97a30 {LuaTest.exe!Square(lua_State *)} {next=0x48575508244c8948 {...} ...} ...} ...}
    l_G: 0x00000218c57021f8 {frealloc=0x00007ff790a4ab60 {LuaTest.exe!l_alloc(void *, void *, unsigned __int64, unsigned __int64)} ...}
    ci: 0x00000218c5702188 {func=0x00000218c570d760 {value_={gc=0xcdcdcdcdcdcdcdcd {next=??? tt=??? marked=??? } ...} ...} ...}
    oldpc: 0xcdcdcdcdcdcdcdcd {???}
    stack_last: 0x00000218c570db50 {value_={gc=0xcdcdcdcdcdcdcdcd {next=??? tt=??? marked=??? } p=0xcdcdcdcdcdcdcdcd ...} ...}
    stack: 0x00000218c570d760 {value_={gc=0xcdcdcdcdcdcdcdcd {next=??? tt=??? marked=??? } p=0xcdcdcdcdcdcdcdcd ...} ...}
    openupval: 0x0000000000000000 <NULL>
    gclist: 0x0000000000000000 <NULL>
    twups: 0x00000218c5702128 {next=0x0000000000000000 <NULL> tt=8 '\b' marked=0 '\0' ...}
    errorJmp: 0x0000000000000000 <NULL>
    base_ci: {func=0x00000218c570d760 {value_={gc=0xcdcdcdcdcdcdcdcd {next=??? tt=??? marked=??? } p=0xcdcdcdcdcdcdcdcd ...} ...} ...}
    hook: 0x0000000000000000
    errfunc: 0
    stacksize: 68
    basehookcount: 0
    hookcount: 0
    nny: 1
    nCcalls: 0
    hookmask: 0
    allowhook: 1 '\x1'

④修改变量

? n=120  //修改整型变量n为120
120
? g_rc.w=10 //修改结构体变量CRect g_rc的成员w为10
10.0000000

⑤执行当前栈帧所在模块中的全局函数

int ImmediateTest1()
{
    return 100;
}

const char* ImmediateTest2()
{
    return "Hello World!";
}

const char* ImmediateTest3()
{
    return "Hello World!\nThis is China.\nLet's go.";
}

std::vector<std::string> ImmediateTest4()
{
    std::vector<std::string> output;
    output.push_back("Hello World!");
    output.push_back("This is China.");
    output.push_back("Let's go.");
    return output;
}

const char* VSDumpLuaStateTValue(lua_State* L, int n)
{
    static char s_szBuffer[256] = { 0 };
    memset(s_szBuffer, 0, 256);

    // ... ...

    return s_szBuffer;
}

 输出结果如下:

? ImmediateTest1()
100
? ImmediateTest2()
0x00007ff790aabb30 "Hello World!"
? ImmediateTest3(),sb
Hello World!
This is China.
Let's go.
? ImmediateTest4()
{ size=3 }
    [capacity]: 3
    [allocator]: allocator
    [0]: "Hello World!"
    [1]: "This is China."
    [2]: "Let's go."
    [Raw View]: {_Mypair=allocator }
? VSDumpLuaStateTValue(L, -1)
0x00007ff790ac0380 "3[-1]: table:0x00000218C5706520"

注1:Immediate窗口中一行的最大字符串长度为230个字符。

注2:格式化符说明

b: unsigned binary integer
bb: unsigned binary integer (without leading 0b)
bstr: BSTR string
c: single character
d: decimal integer
e: scientific notation
en: enum
env: Environment block (double-null terminated string)
f: floating point
g: shorter of scientific or floating point
h: hexadecimal integer
H: hexadecimal integer
hb: hexadecimal integer (without leading 0x)
Hb: hexadecimal integer (without leading 0x)
hr: HRESULT or Win32 error code.
hv: Pointer type - indicates that the pointer value being inspected is the result of the heap allocation of an array
na: Suppresses the memory address of a pointer to an object.
nd: Displays only the base class information, ignoring derived classes
nr: Suppress "[Raw View]" item
nvo: numeric value only
o: unsigned octal integer
s: const char* string
s32: UTF-32 string
s32b: UTF-32 string (no quatation marks)
s8: UTF-8 string
s8b: UTF-8 string (no quatation marks)
sb: const char* string (no quatation marks)
su: Unicode(UTF-16 encoding) string
sub: Unicode(UTF-16 encoding) string (no quatation marks)
wc: Window class flag
wm: Windows message numbers
x: hexadecimal integer
X: hexadecimal integer
xb: hexadecimal integer (without leading 0x)
Xb: hexadecimal integer (without leading 0x)

⑥ 执行当前栈帧ue4全局函数

?{,,UE4Editor-Core-Win64-Debug}::PrintScriptCallstack()  // 打印蓝图调用堆栈
[2021.08.13-17.43.23:445][462]LogOutputDevice: Warning: 

Script Stack (2 frames):
ThirdPersonExampleMap_C.ExecuteUbergraph_ThirdPersonExampleMap
ThirdPersonExampleMap_C.ReceiveBeginPlay

<void>

14. Command窗口

通过命令来完成vs中的功能(不仅仅在调试状态时使用),另外其调试相关命令与windbg保持一致。

? nLocal  //查看变量nLocal的值
?? nLocal //将nLocal添加到Quick Watch窗口中
? nLocal=100 //修改nLocal的值为100
? MySum(20,30) //调用全局函数MySum,并返回结果
k //打印当前线程堆栈
~ //查看线程情况
~*k  //打印出所有线程的堆栈信息
watch //打开watch窗口
memory2 //打开memory2窗口
g //继续执行,F5功能
q //结束调试

15. 内存断点

注:纯Native的c++项目工程才能使用内存断点,开了CLR的c++项目工程则不行;另外,需在调试中断时,才能新建内存断点

(1)在84行断点停住后,查看&s.Age的地址为0x0042FCEC

(2)点击"Debug"-"New Breakpoint"-"New Data Breakpoint...",在弹出的对话框Address填入:0x0042FCEC,长度为4即可

(3)当运行到88行时,由于Scores数组越界引发了s.Age的内存修改,触发了内存断点

16. 条件断点

宏变量名含义
$ADDRESS当前指令
$CALLER调用函数名
$CALLSTACK“调用堆栈”
$FUNCTION当前函数名
$PID进程 ID
$PNAME进程名称
$TID线程 ID
$TNAME线程名

断点说明:

(1)设置断点条件:i>6;且被命中次数>=2时才断住程序,所以第一次断住时i=8

(2)命中时,在Output窗口中打印当前函数名及线程ID(也可以打印相关变量的值,详见"When Breakpoint Is Hit"面板上的说明);在Command窗口中打印出堆栈信息

(3)若不想断住程序,可以把"When Breakpoint Is Hit"对话框中的"Continue execution"勾选上

注1:对于字符串的条件断点,不能写如下条件pStr=="Hello"(pStr为char*类型),应该写成:pStr[0]=='H' && pStr[1]=='e' && pStr[2]=='l' && pStr[3]=='l' && pStr[4]=='o' && pStr[5]=='\0'

     vs2010及以上版本中,条件断点中可使用字符串:strcmp(pStr, "Hello")==0

     支持的字符串函数有:strlen, wcslen, strnlen, wcsnlen, strcmp, wcscmp, _stricmp, _wcsicmp, strncmp, wcsncmp, _strnicmp, _wcsnicmp, strchr, wcschr, strstr, wcsstr.

注2:也可以创建自己的宏,具体方法:"Tools"-"Macros"-"Macro Explorer",然后在下图:MyMacros-Module1上右键快捷菜单中选择"New macro",

     如ChangeExpression宏函数会在Output窗口的Debugger过滤器下打印出"Hello World",然后修改变量code的值为1000

     编写自己的宏时,可以参考大量vs已有的宏(见:Samples节点下)

Public Module Module1
    Function GetOutputWindowPane(ByVal Name As String, Optional ByVal show As Boolean = True)
        Dim window As Window
        Dim outputWindow As OutputWindow
        Dim outputWindowPane As OutputWindowPane

        window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
        If show Then window.Visible = show
        outputWindow = window.Object
        Try
            outputWindowPane = outputWindow.OutputWindowPanes.Item(Name)
        Catch ex As Exception
            outputWindowPane = outputWindow.OutputWindowPanes.Add(Name)
        End Try
        outputWindowPane.Activate()
        Return outputWindowPane
    End Function


    Sub ChangeExpression()
        Dim bppane As EnvDTE.OutputWindowPane

        bppane = GetOutputWindowPane("Debugger")
        bppane.OutputString("Hello World")
        DTE.Debugger.ExecuteStatement("code = 1000;")
    End Sub
End Module

注3:如果弹出以下框,表明vs没有开启macro权限(Tools -- Options... -- Environment -- Add-in/Macro Security中勾选“Allow macros to run”)

注4:2014.2月windows系统更新后,各个版本的vs的宏失效。

        详见:Visual Studio 2010 Macros Stop Working after February 2014 Windows Update | Making Visual Studio perfect

        vs2005sp1补丁  vs2008sp1补丁   vs2010sp1补丁

17.在windows API上打断点

(1)例如:对SetWindowText打断点。首先当前程序字符集为未设置或多字节,则SetWindowTextA;为Unicode则为SetWindowTextW。下面以SetWindowTextA为例。

(2)调试运行程序断住后,打开Modules窗口可以看到所有已经加载的模块,找到windows API所在的模块,右击鼠标执行"Load Symbols From" - "Microsoft Symbol Servers"下载并加载对应模块的pdb

(3)新建一个Break At Function断点,填入:{,,user32.dll}_SetWindowTextA@8。可以看到,VS里面的符号跟windbg相比多了一些字符,其中‘_’表示stdcall类型,后面‘@8’表示所有参数的字节数的和。

       有些函数Symbol Name与导出函数名可能不一致,例如GetDC(HWND),其Symbol Name为NtUserGetDC,最后断点应填入:{,,user32.dll}_NtUserGetDC@4

       注:查找windows API符号名可以使用windbg的x命令或者使用pdb解析工具(symView)

也可以直接使用地址对windows API打断点(这种方式不需要符号的支持):如对GetDC打断点,可以用Dependency查看其在user32.dll中导出函数地址(Entry Point列):0x000172CC

然后在Modules窗口中获得user32.dll模块起始地址0x75840000,最后对两个值相加后的绝对地址处直接设置断点:{,,user32.dll}0x758572CC

通过以上方法也可以给malloc函数(vs2008 debug其dll为msvcr90d.dll,release的dll为msvcr90.dll;在UE4 vs2017的dll为ucrtbase.dll)打上断点

18. 异常(First-chance)时断住程序

在调试程序时,Output窗口有时会出现“First-chance exception in xxx.exe...”这样的信息。
一般来说,这是由于程序中发生了异常,被调试器捕获而产生的输出。
在调试器中运行程序时,如果程序产生异常,调试器会首先获得通知(即First-chance exception)。
若程序没有捕获该异常,则在结束进程之前,操作系统会再次通知调试器(即Second-chance exception,Last-chance exception)。

(1)在"Debug"-"Exceptions...",弹出如下对话框:点击Add按钮,新增一个int类型的C++ Exceptions异常,并勾选Thrown

(2)当int、int*、int&的异常被catch到时,会断住程序进入调试状态(注:以上void类型对应:char*、void*的异常)

19. 单步调试自动跳过不必进入的函数  (注:仅适用于Native c++)

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\NativeDE\StepOver]
"1"="\\scope:CString.*\\:\\:.*=NoStepInto"

注1:如果是32位windows,删除上面路径中的Wow6432Node

注2:不进入任何CString的方法(前面的1表示优先级,该值越大优先级越高)

++++++++++++++++++++++++++++++

NoStepInto 不可进入匹配函数
StepInto   可进入匹配函数

特殊字符串:

\cid 代表一个C/C++标识符
\funct 代表一个C/C++函数名
\scope 代表一个函数的作用范围(命名空间+类名 如:ATL::CFoo::CBar::)
\anything 代表一个字符串
\oper 代表一个C/C++操作符

正则表达式:

\ 转义字符 如:要使用 “\” 本身, 则应该使用“\\”
\: 代表字符:
. 匹配任意字符
* 其左边的字符被匹配任意次(0次或多次)。如:be*匹配“b”,“be”或“bee”
.* 匹配0个或多个字符

更多例子:

例1:不进入重载操作符函数:
10 \scope:operator\oper:=NoStepInto
例2:除了CComBSTRs的非操作符函数,不进入任何ATL::开头的函数:
20 ATL\:\:CComBSTR::\funct:=StepInto
10 ATL\:\:.*=NoStepInto
例3:除了全局模版函数外,不进入任何模板函数:
20 \scope:\funct:=StepInto
10 .*[\<\>].NoStepInto

++++++++++++++++++++++++++++++

20. 使用OutputDebugString进行日志调试

(1)调试状态时,会将日志输出到Debug过滤器的Output窗口中

(2)非调试状态时,可采用DbgView.exe来捕捉程序日志

21. 使用autoexp.dat自定义调试时变量的显示格式

文件所在位置:Microsoft Visual Studio 9.0\Common7\Packages\Debugger\autoexp.dat

在autoexp.dat中的[Visualizer]域可以对各种类型变量的显示格式进行配置,来优化变量在调试时显示,提高效率。

注1:在vs中要让autoexp.dat生效需要去掉"Tools"-"Options..."对话框中,

     "Debugging"-"General"-"Show raw structure of objects in variables windows"的勾选

注2:vs2012版本后,autoexp.dat被废弃,改用.natvis文件,该文件需要安装到"%USERPROFILE%\Documents\Visual Studio 2012\Visualizers"目录中

    如UE4引擎源码中的%EngineDir%\Engine\Extras\VisualStudioDebugging\UE4.natvis

(1) STL之string、vector、map

①原始显示结果:

②配置了autoexp.dat的显示结果:

-->对应的配置内容如下:

;  std::string -- char
std::basic_string<char,*>{
    preview        ( #if(($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,s]) #else ( [$e._Bx._Ptr,s]))
    stringview    ( #if(($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,sb]) #else ( [$e._Bx._Ptr,sb]))
    children
    (
        #if(($e._Myres) < ($e._BUF_SIZE))
        (
            #([actual members]: [$e,!] , #array( expr: $e._Bx._Buf[$i], size: $e._Mysize))
        )
        #else
        (
            #([actual members]: [$e,!],  #array( expr: $e._Bx._Ptr[$i], size: $e._Mysize))
        )
    )
}
;------------------------------------------------------------------------------
;  std::vector
;------------------------------------------------------------------------------
std::vector<*>{
    children
    (
        #array
        (
            expr :        ($e._Myfirst)[$i],
            size :        $e._Mylast-$e._Myfirst
        )
    )
    preview
    (
        #(
            "[", $e._Mylast - $e._Myfirst , "](",
            #array
            (
                expr :    ($e._Myfirst)[$i],
                size :    $e._Mylast-$e._Myfirst
            ),
            ")"
        )
    )
}
;------------------------------------------------------------------------------
;  std::map
;------------------------------------------------------------------------------
std::map<*>{
    children
    (
        #tree
        (
            head : $e._Myhead->_Parent,
            skip : $e._Myhead,
            size : $e._Mysize,
            left : _Left,
            right : _Right
        ) : $e._Myval
    )
    preview
    (
        #(
            "[", $e._Mysize, "](",
            #tree
            (
                head : $e._Myhead->_Parent,
                skip : $e._Myhead,
                size : $e._Mysize,
                left : _Left,
                right : _Right
            ) : $e._Myval,
            ")"
        )
    )
}

(2) 自定义类MyArray

①原始显示结果:

②配置了autoexp.dat的显示结果:

-->对应的配置内容如下:

MyArray{
    preview
    (
        #(
            "[size is ", $c.m_nSize, "] m_pData is (",
            #array
            (
                expr: ($c.m_pData)[$i],
                size: $c.m_nSize
            ),
            ")..."
        )
    )
    stringview
    (
        #(
            "Hello MyArray!!!"
        )
    )
    children
    (
        #(  
            #array
            (
                expr: ($c.m_pData)[$i],
                size: $c.m_nSize
            )
        )
    )
}

注1:双引号中字符串不能含有冒号,如:"[size is "不能写成"size: "

注2:多个类型使用 | 进行连接。如:MyArray|ArrayEx

注3:preview、stringview及children。对于不需要的部分可以不用定义,且三个部分没有先后顺序之分。

注4:格式的定义的最外层用大括号{},其中的每个部分使用小括号()。

注5:格式定义出错时,运行VS会弹出提示窗口,对于格式配置错误的类型,在调试期间无法正常显示。

注6:最外层的左边的大括号{必须紧挨着最后一个类型名,否则无论后面的格式正确与否,都无法正常显示。

注7:符号;为行注释符。

注8:c表示当前所定义数据结构的对象,#array表示用数组形式显示内容,c表示当前所定义数据结构的对象,#array表示用数组形式显示内容,i表示数组中的每个元素的索引,$e表示数组中的每个元素的值

注9:array结构必须同时包含expr和size两个部分,缺少其中一个部分都将导致信息无法正确显示。

注10:可使用#switch、#if进行条件分支判断,要注意的是:#switch结构不能用于#array结构中,否则可能导致VS挂死。

Visual Studio调试技巧:监视窗口的高级应用 调试是软件开发中不可或缺的环节,而变量监视作为调试技术的核心手段,能够实时追踪程序状态变化。其原理是通过IDE的调试接口获取运行时内存数据,以可视化形式呈现给开发者。在Visual Studio中,监视窗口(Watch Window)支持条件表达式、格式化显示等高级功能,大幅提升复杂业务逻辑(如财务计算)和内存泄漏等问题的排查效率。结合断点调试和性能分析工具,开发者可以快速定位数组越界、多线程竞争等典型问题,是提升C#/.NET开发效率的关键实践。 阅读详情

相关推荐

Visual Studio 调试器:设置和使用断点_2024-07-23_04-28-17.Tex

断点是Visual Studio调试器的核心功能之一,它为开发者提供了一种强大的工具来理解和定位代码中的错误。通过设置断点,你可以暂停程序执行,检查变量状态,跟踪函数调用,这对于任何级别的开发者来说都是一个不可或缺的技能。掌握断点的使用,将大大提高你的代码调试效率和质量。

1621

devc调试设置断点后没有反应_简单聊聊VisualStudio的断点调试

这节聊聊如何使用VisualStudio进行断点调试。 在debug过程中,我们有时需要查看程序在运行到某一行代码时,上下文中的变量或者一些其他的数据是什么样的,我们就要设置断点(Breakpoint)。断点顾名思义,就是运行到打断点的这一行,程序就中断,暂停。下面就看看如何使用VisualStudio来断点调试C#代码。如何断点: 在VS中,如何为代码设置断点呢,有这么两种形...

weixin_39732825的博客 1682

45、Visual Studio调试:高级技巧与工具解析

本文深入解析了Visual Studio调试的高级技巧与工具,重点介绍了DebuggerDisplayAttribute、DebuggerBrowsableAttribute和DebuggerTypeProxyAttribute等调试属性的使用方法,以及转储文件处理和调试工具如WinDbg和Son of Strike的使用。同时,讨论了调试的不同方式、类型及优化控制,帮助开发者在复杂环境和问题中高效定位和解决。

alpha的博客 82

[原译]11个高效的VS调试技巧

介绍 调试是软件开发周期中的一个很重要的部分,有时很有挑战性,有时候则让程序员迷惑,有时候让程序员发疯,但是。可以肯定的是,对于任何不是太那个微不足道的程序来说,调试是不可避免的。近年来,调试工具的发展已经使得很多调试任务简单省时了。 本文总结了十个调试技巧,当你使用VS的时候可以节省你很多时间。 1.悬停鼠标查看表达式 调试有时候很有挑战性,当你步入一个函数想看看哪块出错的时候...

weixin_33882443的博客 1004

Visual Studio Debugger:调试Web应用程序_2024-07-23_06-12-26.Tex

Visual Studio Debugger是Microsoft Visual Studio集成开发环境(IDE)中一个强大的工具,用于调试各种类型的代码,包括Web应用程序。它提供了丰富的功能,如设置断点、单步执行、查看变量值、调用堆栈分析等,帮助开发者定位和修复代码中的错误。

804

Windows高级调试 中英文 PDF

Windows高级调试 中英文 PDF advanced windows debugging,希望对你有帮助。

【工具-3】Visual Studio高级调试技巧

1. 设置软件断点,运行到目标位置启动调试器 方法①:使用汇编指令(注:x64 c++不支持嵌入汇编) _asm int 3 方法②:编译器提供的方法 __debugbreak(); 方法③:使用windows API DebugBreak(); WerFault.exe进程(Windows Error Reporting)弹出ConsoleTest.exe已停止工作: 要...

做一个合格的渣渣 983

SikuliX实战:5分钟搞定游戏挂机脚本(附防检测思路与Python集成技巧)

本文详细介绍了如何使用SikuliX快速开发游戏挂机脚本,包括环境配置、基础原理、防检测策略及Python集成技巧。通过实战案例展示如何实现自动化任务、高级防检测方案,并结合Python提升脚本性能与智能度,帮助玩家高效完成重复性游戏操作。

weixin_33228769的博客 337

Visual Studio Code 高级使用技巧:插件推荐、调试技巧与工作流优化

根据个人需求自定义快捷键,可以大幅提升工作效率。打开设置(在快捷键面板中找到想要修改的命令,右键点击并选择“更改快捷键”。输入新的快捷键组合并保存。

好看资源网的博客 1871

Arm CCA架构:硬件级机密计算与安全隔离技术解析

机密计算(Confidential Computing)通过硬件级隔离技术构建可信执行环境(TEE),是当前云安全和数据隐私保护的核心方案。Armv9-A引入的CCA架构采用物理地址空间隔离和Granule保护表(GPT)机制,实现4KB颗粒度的内存访问控制。该技术通过标准化的RMI/RSI接口规范,为虚拟化环境和安全敏感应用提供硬件级保护,特别适用于金融交易、医疗数据处理等需要严格隔离的场景。相比传统TEE方案,Arm CCA在隔离等级和动态权限管理方面具有显著优势,其Realm World设计为机密计算

weixin_30905133的博客 566

实现飞书机器人推送消息到指定群组或者用户

飞书是一个集成了聊天、协作和办公功能的企业级平台,广泛应用于企业内部沟通和协作。飞书机器人(Feishu Bot)是一种强大的工具,允许开发者通过编程接口与飞书进行互动,从而实现自动化消息推送和任务管理。本文将详细介绍如何通过飞书机器人推送消息给指定的人或者群组,帮助您快速上手。

qq_41898196的博客 5872

Visual Studio调试技巧与高级功能实战指南

调试是软件开发中不可或缺的核心技能,Visual Studio作为主流IDE提供了强大的调试工具链。从基础断点设置到内存分析,调试器通过运行时上下文检查、变量监控和流程跟踪等机制,帮助开发者快速定位代码缺陷。在性能优化领域,CPU热点分析和内存诊断工具能有效识别资源瓶颈,而多线程调试功能则为解决并发问题提供了可视化手段。通过条件断点、跟踪点等高级技巧,开发者可以在不修改代码的情况下收集运行时信息。这些技术在大型项目维护、性能调优和生产环境问题诊断等场景中尤为重要,如使用转储文件分析线上崩溃,或通过远程调试定

weixin_28842367的博客 282

Android 的端智能学习路径

基础层:先补齐 Android 进阶(JNI / 性能优化)和 AI 基础概念,无需深入算法开发;核心层:掌握 TFLite 的模型加载、推理、量化,能完成基础端侧推理;落地层:聚焦实战场景(图像 / OCR / 语音),解决工程化问题(模型管理、异常处理);优化层:通过模型量化、硬件加速、工程优化,提升推理性能和用户体验。

hqiangtai的博客 346

Visual Studio Uninstaller高级用法:命令行参数与调试技巧全解析

Visual Studio卸载工具是微软官方提供的终极解决方案,专门用于彻底清理Visual Studio 2012-2015版本的残留文件。🚀 当常规卸载失败时,这款工具能帮你完全移除那些顽固的安装痕迹,避免重装系统的麻烦。 ## 🔧 核心命令行参数详解 ### 基础操作参数 **1. 帮助命令** 使用 `help`、`/help` 或 `/?` 参数可以快速查看工具的使用说明:

gitblog_00839的博客 716

[Vue][面试]谈谈你对MVC、MVP和MVVM的理解

谈谈你对MVC、MVP和MVVM的理解 答题思路:此题涉及知识点很多,很难说清楚,说透彻,因为MVC,MVP这些我们前端程序员自己甚至都没用过。但是恰恰反映了前端这些年从无到有, 从有到优的变迁过程,因此沿此思路回答将十分清除。 Web1.0时代 在web1.0时代,并没有前端的概念。开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常由多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、C#/Java/PHP代码, 系统整体架构可能如下图所

你好,欢迎光临! 725

工商银行数据智能架构实践

工商银行大数据平台技术创新与实践摘要(149字): 工商银行构建了企业级大数据云基础设施,形成包含批量计算、流计算、联机分析等核心能力的技术架构。平台创新性地实现流批一体处理,将个人储蓄存款监测时效提升至分钟级;通过实时数仓技术将报送时效缩短至1-5分钟;融合内外部数据构建风控模型,债券违约预警准确率达100%。平台还支撑了"码上赢"精准营销和空间数据服务等创新应用,未来将向存算分离、实时数仓和云数智融合方向演进,持续提升数据价值转化能力。

银行信息系统应用架构详解 541

bflat高级调试技巧:原生C程序的GDB和Visual Studio调试指南

bflat是一款将C#与Go风格工具链结合的编译器,能生成小巧、自包含的原生可执行文件。本文将详细介绍如何使用GDB和Visual Studio调试bflat编译的原生C#程序,帮助开发者快速定位问题并优化代码。 ## 📋 调试前的准备工作 ### 编译时启用调试信息 bflat默认会为程序生成调试信息,但不同平台的处理方式略有差异: - **Linux系统**:默认将DWARF调试信息包含

gitblog_00179的博客 318

微信小程序 - request:fail errcode:10011 cronet_error_code:0 error_msg:network change, cancel all task请求报错

微信小程序请求接口,报request:fail errcode:10011是什么原因,uniapp微信小程序request:fail errcode:10011 cronet_error_code:0 error_msg:network change, cancel all task,微信小程序wx.request常规访问接口,有个别用户的接口请求频繁报错,UniApp 微信小程序uni.request请求接口报错:request:fail errcode:10011 的原因分析与解决方案,苹果ios,安卓

🏆 前端领域优质创作者 4568

Visual Studio高级调试技巧与实战配置指南

调试是软件开发中的核心技能,通过符号文件(.pdb)和断点机制,调试器能够精确映射二进制执行与源代码的关系。现代IDE如Visual Studio提供了从基础断点到时间旅行调试(TTD)的全套工具链,其技术价值在于能显著提升复杂问题的诊断效率。在Web开发、多线程编程等场景中,合理的异常设置与远程调试配置尤为重要。本文重点解析Visual Studio调试环境中的符号服务器配置、条件断点设置等实用技巧,并介绍如何利用性能分析工具定位内存泄漏问题。掌握这些方法能帮助开发者应对90%的调试挑战,特别是处理偶发性

weixin_31842715的博客 207

【车载以太网】【AVB/TSN】IEEE802.1Qav队列及转发协议

目录 一、概述 二、优先级排队算法 三、基于信用的流量整形算法 一、概述 IEEE 802.1Qav 队列及转发协议(Qav)针对不同数据流选择不同的传输选择算法来保障对时间敏感的 AV 数据流的实时传输。为了避免传统的异步以太网数据流量与 AVB 流量之间对网络资源的竞争,AVB 交换机内使用优先级排队算法和基于信用的流量整形算法实现数据流的调度。 二、优先级排队算法 优先级排队算法主要用于传统以太网数据流(BE, Best Effort)的调度传输,BE 流通过基于优先级...

专注汽车软件开发、AutoSAR、车载以太网、SOA、EE架构。 4688

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Windows多线程调试实战:Visual Studio高级技巧与应用

多线程编程是现代软件开发的核心技术,尤其在Windows平台下,合理利用调试工具能显著提升并发问题排查效率。线程同步机制如互斥锁、条件变量等基础概念,是保证线程安全的关键原理。通过Visual Studio的线程窗口、跟踪点和条件断点等调试技术,开发者可以精准定位死锁、竞态条件等典型并发问题。这些方法在工业控制系统、金融交易平台等高并发场景中具有重要价值。结合生产者-消费者模型实例,文章详解了如何利用数据断点分析共享资源访问,以及通过并行堆栈视图诊断线程阻塞问题。对于涉及16个传感器通道的数据采集系统等复杂

weixin_28736145的博客 277

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Visual Studio Code 高级使用技巧:插件推荐、调试技巧与工作流优化实战

VS Code 插件装多了启动慢、调试配置繁琐?本文提供可复制的 settings.json 与 launch.json 骨架、精选插件清单,并演示如何通过 TaoToken 统一 Key 与 API 通道接入 AI 编程助手,官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 可注册获取。

weixin_34064233的博客 136

VC中sqlite的使用

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

Visual Studio调试实战:监视窗口与断点高级用法,数组监视技巧详解

调试是软件开发中绕不开的环节,而高效定位问题往往取决于对调试工具的深度理解。在C++与C#工程实践中,断点(Breakpoint)与监视窗口(Watch Window)是两大核心利器,但多数开发者只停留在基础操作层面,难以应对数组、指针、多线程等复杂场景。本文从调试器的基本机制出发,系统拆解条件断点、命中次数、数据断点以及格式化修饰符的实战价值,并重点剖析数组监视的高效技巧——通过数量修饰符、表达式监视与动态容器观察,让大块内存数据一目了然。这些方法可广泛应用于缓冲区溢出排查、链表遍历、字符串乱码分析等高频

weixin_28835583的博客 273
上一篇: linux screen 命令详解(转)
下一篇: Visual Studio调试器指南---Natvis 语法参考
UU_Yang
博客等级 码龄23年 926粉丝 213原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值