Skip to content

Commit

Permalink
03.05 -> 03.06
Browse files Browse the repository at this point in the history
  • Loading branch information
ficapy committed Jan 5, 2021
1 parent ef8e059 commit 285aa68
Showing 1 changed file with 180 additions and 19 deletions.
199 changes: 180 additions & 19 deletions 03DebugC++程序/3.6 使用集成调试器,单步调试.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,146 @@

本章的剩余部分将用来学习如何使用调试器。

### 提示
> ### 提示
>
> 不要忽视学习使用调试器。随着你的程序变得越来越复杂,与你节省的查找和修复问题的时间相比,你花在学习有效使用集成调试器上的时间就显得微不足道了。
>
> ### 警告
>
> 在继续学习本课之前(以及后续和使用调试器相关的课程),请确保你的项目使用调试器配置进行编译(参考0.9节 -- 配置你的编译器--构建配置 章节)。如果你使用发布配置来编译你的项目,调试器的功能可能无法正常工作。
>
> ### 对于Code::Blocks用户
>
> 如果你使用的是Code::Blocks,你的调试器可能会或者不会被正确设置。让我们来检查一下。
>
> 首先,进入 设置菜单 -->> 调试器 -->> GDB/CDB debugger, 选择Default。应该打开以下对话框,看起来像这样
>
> ![img](https://blogimg.ficapy.com/learncpp/CB-DebuggingSetup-min.png)
>
> 如果你看到"可执行文件路径"的地方有一个大红条,那么你需要找到你的调试器。要做到这一点,点击“可执行路径”字段右边的按钮,在你的系统中找到gdb32.exe文件。存在于以下目录"*C:\Program Files (x86)\CodeBlocks\MinGW\bin\gdb32.exe*."。然后点击确定。
>
> ### 对于Code::Blocks用户
>
> 有报告称,Code::Blocks集成调试器(GDB)在识别一些包含空格或者非英文字符的路径时可能出现问题。如果你在学习这些课程的时候遇到问题,这可能是一个原因。
>
不要忽视学习使用调试器。随着你的程序变得越来越复杂,与你节省的查找和修复问题的时间相比,你花在学习有效使用集成调试器上的时间就显得微不足道了。
# 单步调试

### 警告
我们要开始对调试器的探索,首先要研究一些调试工具,让我们能够控制程序的执行方式。

在继续学习本课之前(以及后续和使用调试器相关的课程),请确保你的项目使用调试器配置进行编译(参考0.9节 -- 配置你的编译器--构建配置 章节)。如果你使用发布配置来编译你的项目,调试器的功能可能无法正常工作
`Stepping`是一组相关调试器功能的名称,它让我们逐条语句执行我们的代码

### 对于Code::Blocks用户
还有一些相关的单步命令,我们将依次介绍

如果你使用的是Code::Blocks,你的调试器可能会或者不会被正确设置。让我们来检查一下。
# Step into

首先,进入 设置菜单 -->> 调试器 -->> GDB/CDB debugger, 选择Default。应该打开以下对话框,看起来像这样
`Step into`命令执行程序正常执行路径中的下一条语句,然后暂停程序的执行,这样我们就可以使用调试器检查程序的状态。如果正在执行的语句中包含一个函数调用,step会让程序跳转到被调用函数的顶端,在那里暂停执行。

![img](https://blogimg.ficapy.com/learncpp/CB-DebuggingSetup-min.png)
让我们来看看一个非常简单的程序:

如果你看到"可执行文件路径"的地方有一个大红条,那么你需要找到你的调试器。要做到这一点,点击“可执行路径”字段右边的按钮,在你的系统中找到gdb32.exe文件。存在于以下目录"*C:\Program Files (x86)\CodeBlocks\MinGW\bin\gdb32.exe*."。然后点击确定。
```c++
#include <iostream>

### 对于Code::Blocks用户
void printValue(int value)
{
std::cout << value << '\n';
}

有报告称,Code::Blocks集成调试器(GDB)在识别一些包含空格或者非英文字符的路径时可能出现问题。如果你在学习这些课程的时候遇到问题,这可能是一个原因。
int main()
{
printValue(5);
return 0;
}
```
# 单步调试
让我们使用step into命令来调试这个程序。
我们要开始对调试器的探索,首先要研究一些调试工具,让我们能够控制程序的执行方式
首先,找到并执行一次单步调试命令
`Stepping`是一组相关调试器功能的名称,它让我们逐条语句执行我们的代码。
> ### 对于Visual Studio用户
>
> 在Visual Studio中,可以通过 Debug -->> Step Into,或者按F11快捷键进入
>
还有一些相关的单步命令,我们将依次介绍
> ### 对于Code::Blocks用户
>
> 在Code::Blocks中,可以通过Debug -->> Step Into,或者按Shift-F7快捷键进入
>
# Step into
> ### 对于其他编译器
>
> 如果使用不同的IDE,你可能会在Debug或者Run菜单下找到Step Into命令
>
`Step into`命令执行程序正常执行路径中的下一条语句,然后暂停程序的执行,这样我们就可以使用调试器检查程序的状态。如果正在执行的语句中包含一个函数调用,step会让程序跳转到被调用函数的顶端,在那里暂停执行。
当你的程序没有运行,你执行第一个调试命令时,你可能会看到下列的事情发生:
让我们来看看一个非常简单的程序:
- 如果需要,程序会重新编译
- 程序开始运行。因为我们的程序是一个控制台程序,所以应该打开一个控制台输出窗口。它将是空的,因为我们还没有输出任何东西。
- 你的IDE可能会打开一些诊断窗口,这些窗口的名称可能是"诊断工具"、"调用栈"、"观察"。我们稍后会介绍其中的一些 -- 现在你可以忽略它们。
因为我们做了一个单步调试,你现在应该看到在main函数(第九行)的开头括号左边出现了某种标记。在Visual Studio中,这个标记是一个黄色的箭头(Code::Blocks使用黄色的三角形)。如果你使用的是不同的IDE,你应该会看到一些具有相同作用的东西。
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line9-min.png)
这个箭头标记表明,下一步将执行指向的行。在本例中,调试器告诉我们,下一行要执行的是main函数的开头括号(第九行)。
选择Step Into(使用适合你的IDE的命令)执行开头的括号,箭头将移动到下一条语句(第十行)
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line10-min.png)
这意味着下一行要执行的是对函数printValue的调用。
再次选择Step Into,因为这条语句包含了对printValue的函数调用,所以我们进入函数,箭头会移动到函数PrintValue顶部。
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line4-min.png)
再次选择Step Into,执行函数PrintValue的开头括号,将箭头推进到第五行。
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line5-min.png)
再次选择Step Into,这将执行语句std::cout << value,并将箭头移动到第六行。
> ### 警告
>
> 因为operator << 是作为函数实现的,所以你的IDE可能会跳转到operator << 的实现。
>
> 如果发生这种情况,你会看到你的IDE打开了一个新的代码文件,箭头标记会移动到一个名为operator << 的函数的顶部(这是标准库的一部分)。关闭刚才打开的代码文件,找到并执行Step Out调试命令(后续章节会说明Step Out的作用)
>
现在因为std::cout << value已经执行,我们现在应该看到值5出现在控制台窗口。
再次选择Step Into, 执行函数printValue的结束括号。此时,printValue已经执行完毕,控制权回到main。
你会注意到,箭头又指向了printValue!
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line10-min-20210105232409869.png)
虽然你可能认为调试器打算再次调用printValue,但是实际上调试器只是让你知道它正从函数调用中返回。
再选择Step Into三次。此时,我们已经执行了程序中的所有行,所以我们已经完成了。有些调试器会在此时自动终止调试会话,有些可能不会。如果你的调试器没有这样做,你可能需要再菜单中找到"Stop Debugging"命令(再Visual Studio中,这是在Debug -> Stop Debugging下面)。
请注意,在调试过程中的任何时候都可以使用Stop Debugging来结束调试会话。
恭喜你,你现在已经完全执行了一个程序,并观看了每一行的执行情况。
# Step over
和step into一样,step over命令也是执行程序正常执行路径的下一条语句。但是,step into会进入函数并且逐行执行,而step over会执行完整个函数,并且在函数执行完毕后将控制权返回给你(简而言之,就是遇到函数调用就不进入调试,直接跳过)
> ### 对于Visual Studio用户
>
> 在Visual Studio中,可以通过 Debug -->> Step Over,或者按F10快捷键访问
>
> ### 对于Code::Blocks用户
>
> 在Code::Blocks中,step over命令被称为next line,可以通过 Debug -->> Next line,或者按F7快捷键进入
>
让我们来看看这个例子,我们调用printvalue函数的时候将使用step over
```c++
#include <iostream>
Expand All @@ -73,5 +178,61 @@ int main()
}
```

让我们使用step into命令来调试这个程序。
首先,使用step into,直到执行标记在第十行

![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line10-min-20210105233721122.png)

现在,选择step over。调试器将执行该函数(在控制台窗口中打印值5),然后在下一条语句(第12行)中将控制权返回给你。

当你确定这些函数已经可以使用,或者现在对调试这些函数不感兴趣的时候,step over命令提供了一种方便的方法。

# step out

和其他两个命令不同的是,step out并不只是执行下一行代码。相反,它执行当前正在执行的函数中的所有剩余代码,然后在函数返回后将控制权返回给你。

> ### 对于Visual Studio用户
>
> 在Visual Studio中,可以通过 Debug -->> Step out,或者按Shift-F11快捷键来访问
> ### 对于Code::Blocks用户
>
> 在Code::Blocks中,可以通过Debug -->> Step out,或者按Ctrl-F7快捷键来访问
让我们用上面同样的程序来看一个例子

```c++
#include <iostream>

void printValue(int value)
{
std::cout << value << '\n';
}

int main()
{
printValue(5);
return 0;
}
```
step into,直到进入到函数printValue内部,执行标记在第4行
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line4-min-20210105234429243.png)
然后选择step out, 你会注意到输出窗口中出现了数值5,在函数终止后,调试器将控制权返回给你(在第十行)。
![img](https://blogimg.ficapy.com/learncpp/VS2019-StepInto-Line10-min-20210105234600596.png)
当你不小心进入一个不想调试的函数的时候,这个命名非常有用。
# 跑过了
当调试一个程序的时候,通常只能往前走一步。很容易不小心跳过了你想debug的地方。
如果你错过了你的预定目标,通常要做的就是停止调试,重新开始调试,要更小心一点,这次不要错过了你的目标。
# step back
一些调试器(比如Visual Studio企业版和GDB 7.0) 引入了一种功能,一般称为回退或者反向调试。step back是后退一步,因此可以将程序回到之前的状态。如果你错过了,或者想重新检查一个刚刚执行的语句,这很有用。
实现回退要求调试器非常复杂(因为它必须跟踪每个步骤的状态)。因为太过复杂,该功能尚未标准化,并且各个调试器各不相同。截止写稿时(2019年1月),无论是Visual Studio社区版,还是最新的Code::Blocks都不支持这个功能,希望在未来的某个时刻,它能加入到这些产品中,并能得到广泛的使用。

0 comments on commit 285aa68

Please sign in to comment.