跳到内容

元数据卡

  • 前置知识:调试器基础(断点 + 步进)
  • 预计时间:15 分钟
  • 阅读模式:高度专注 + 边读边敲
  • 完成标志:能用条件断点、读调用栈、在 WATCH 面板中写表达式

你的进度

基础断点让你能停住程序看变量。但问题更狡猾了——一万步工序里只有一个步骤有 bug,你不想每次都按 F10。或者你看到了一个错误的值,但不知道是谁把参数传错了。

这时候你需要更精细的工具。


第二场战斗:只在特定条件下停住

你的锻造流程有一万个步骤,你怀疑某一步签入的参数不对。但每次设断点,前 9999 步都停住——你得一直按 F5 跳过。

你不需要在循环里每个元素都停——你可以在特定条件下才断住。

在 VS Code 里,右键点击断点 → 选择"Edit Breakpoint…":

python
for it in items:
if it["weight"] == 99999:  # ← 只有当重量等于 99999 时才停
    valid.append(it)

如何设置: 右键红点,输入条件表达式 it["weight"] == 99999效果: 前面 weight = 100weight = 200 都不停。直到那万中无一的 weight = 99999——啪,停住了。

条件断点的本质: 同一个断点,加了一个"门卫"。程序每次经过这行都检查条件——条件为 true 才停。这叫无副作用的观察——不影响程序性能,不影响状态。


第三场战斗:谁把我叫到这里来的?

淬火池的温度读数返回了 0,但你知道它不该是 0。你在温控函数里设了断点——停下了,参数正常。但问题在调用者——谁传进来的参数?

你需要回溯调用链条。

python
# forge_calculator.py
def calc_material_cost(item_id, weight):
    discount = get_alloy_discount(weight)

def get_alloy_discount(weight):
    ratio = get_discount_ratio()
    return weight * ratio

def get_discount_ratio():
    return 0  # 总是 0 —— bug 在这里!

get_alloy_discount 设断点。程序停住后看 CALL STACK 面板:

CALL STACK
 get_alloy_discount (forge_calculator.py:6)
 calc_material_cost (forge_calculator.py:3)
 <module> (forge_calculator.py:10)

阅读方向:从下往上。

  • <module> 是入口
  • calc_material_cost 调用了 get_alloy_discount
  • 当前停住的是 get_alloy_discount(最上面一行)

你双击 calc_material_cost——调试器带你跳到调用者那一行,所有变量状态都保留着。这就是调试器的"时空穿梭"。


第四场战斗:让我算算这个表达式

你看到了变量的值——铁锭重量 = 100,杂质比例 = 0.1。但你想知道 weight * (1 - ratio) 等于多少。你不想在代码里加一个新变量来存——这轮调试完还得删。

WATCH 面板里输入表达式:

WATCH
 weight * (1 - ratio): 90.0
 round(weight * (1 - ratio), 2): 90.0

如何运行: 在断点停住时,WATCH 面板下方点"+",输入任意 Python/Java 表达式 效果: 调试器在当前上下文中求值,实时显示结果

你也可以在 调试控制台(Debug Console) 里写更复杂的表达式:

>>> weight * (1 - ratio)
90.0
>>> [it["weight"] for it in items if it["weight"] > 100]
[200, 99999]

甚至可以修改变量的值:

>>> n = 100  # 临时把 n 改成 100,程序继续跑会用到这个新值

小心: 在调试控制台修改变量不是模拟——你是真的在改内存。可以用来测试边界情况,但要记得恢复。


日志断点:不想停,只想看

有时候你不想停程序,只想看变量在每次循环里的变化——但又懒得写 print()

右键断点 → 选择"Log Message"(VS Code),输入消息模板:

python
# 日志断点:不暂停,只输出
  # Log message: "当前工件 ID: {m['id']} 重量: {m['weight']}"

效果: 程序不会停,但调试控制台会打印:

当前工件 ID: 1 重量: 100
当前工件 ID: 2 重量: 0
当前工件 ID: 3 重量: 200

这是"零侵入"调试——日志不是代码,关掉调试模式就消失了。不用删。


附录:GDB(不写 C/C++ 可以跳过)

GDB(GNU Debugger)是命令行版的调试器,概念同 IDE 调试器:

bash
# 编译时加 -g 包含调试信息
gcc -g myprog.c -o myprog
gdb ./myprog

# GDB 内部
(gdb) break main      # 设断点
(gdb) run              # 运行
(gdb) print x          # 看变量 x
(gdb) next             # 步过
(gdb) step             # 步进
(gdb) backtrace        # 看调用栈
(gdb) quit

语言: Bash / GDB 如何运行: gcc -g program.c -o program && gdb ./program

当你只能 SSH 到一个没有桌面的服务器上 debug 时,GDB 是你唯一的可能。暂时用不到——但知道它存在就够了。


下一步

进阶工具在手,但脑子里还不够熟练。下一站给你一个调试练习场——热身题、递归挑战、以及几个专门设计的排障场景。

Built with VitePress | Software Systems Atlas