Lua中debug调试函数详解

更多信息 进群了解
QQ群:756167961

Lua 的 debug 库提供了一系列用于调试和运行时内省的工具函数。以下是常用函数的详细说明及示例:


1. debug.debug()

  • 作用:启动交互式调试控制台,允许手动输入调试命令(如查看变量、控制执行流)。
  • 注意:实际开发中较少直接使用,通常依赖外部调试器。
  • 示例
    function test()
      debug.debug()  -- 进入调试控制台
    end
    test()
    -- 输入命令如 `print(a)` 查看变量
    

2. debug.gethook([thread])

  • 作用:获取当前线程(或指定线程)的钩子设置。
  • 返回值:钩子函数、钩子掩码(事件类型)、钩子触发计数。
  • 钩子掩码
    • 'c':调用事件。
    • 'r':返回事件。
    • 'l':行事件(执行新行时触发)。
  • 示例
    local hook, mask, count = debug.gethook()
    print(mask)  --> 当前钩子的事件类型(如 'clr')
    

3. debug.getinfo([thread,] func [, what])

  • 作用:用于获取函数的相关信息。

函数参数

  • thread:可选参数,是一个线程对象。若提供了该参数,函数会获取此线程内指定函数的信息;若未提供,默认使用当前线程。
  • func:必选参数,既可以是一个函数,也可以是一个返回函数调用信息的栈层次索引(整数)。若为栈层次索引,1 代表当前函数,2 代表调用当前函数的函数,依此类推。
  • what:可选参数,是一个字符串,用于指定要获取的信息类型。该字符串可由以下字符组合而成:
    • "n":获取函数的名称和其所属的表域名称。
    • "f":返回函数本身。
    • "S":获取函数的一些静态信息,像函数的源文件、起始行和结束行等。
    • "l":获取函数调用发生的行号。
    • "u":获取函数的上值(upvalue)数量。
    • "t":判断函数是否为 C 函数,若是则返回 "C",否则返回 nil
    • "L":获取一个表,表中记录了函数中哪些行是有效的(即会被执行的)。

返回值

此函数返回一个包含信息的表(如 sourcelinedefined)。表中的字段会依据 what 参数的不同而有所变化。以下是可能出现的字段:

  • name:函数名。
  • namewhat:函数名称的类型,如 "global""upvalue"等。
  • func:函数本身。
  • source:函数定义所在的源文件,若函数是在字符串中定义的,该字段会以 @ 开头。
  • short_src:源文件的简短名称。
  • linedefined:函数定义的起始行号。
  • lastlinedefined:函数定义的结束行号。
  • currentline:函数调用发生的行号。
  • nups:函数的上值数量。
  • istailcall:是否为尾调用。
  • what:函数的类型,如 "Lua""C""main" 等。
  • activelines:一个表,记录函数中哪些行是有效的。
  • nparams:函数参数个数。
  • ntransfer
  • ftransfer
  • isvararg

示例代码

local info = debug.getinfo(print)
print(info.source)  --> [C](表示 C 函数)

function foo() 
  local info = debug.getinfo(1)  -- 获取当前函数信息
  print(info.currentline)        --> 4(行号)
end
foo()

function exampleFunction()
    local info = debug.getinfo(exampleFunction, "nSlu")
    print("Function name: ", info.name)
    print("Source file: ", info.source)
    print("Line defined: ", info.linedefined)
    print("Current line: ", info.currentline)
    print("Number of upvalues: ", info.nups)
end

exampleFunction()

4. debug.getlocal([thread,] level, idx)

  • 作用:获取指定堆栈帧的局部变量名和值。
  • 参数
    • level:堆栈层级(0 为当前函数)。
    • idx:局部变量索引(从 1 开始)。
  • 返回值:变量名和值(若存在)。
  • 示例
    function test(a, b)
      local x = 10
      local name, value = debug.getlocal(1, 3)  -- 第三个局部变量
      print(name, value)  --> "x", 10
    end
    test(1, 2)
    

5. debug.getmetatable(value)

  • 作用:获取值的元表,忽略 __metatable 的保护。
  • 对比:普通 getmetatable 会受 __metatable 限制。
  • 示例
    local t = {}
    setmetatable(t, { __metatable = "protected" })
    print(getmetatable(t))       --> "protected"
    print(debug.getmetatable(t)) --> table:...
    

6. debug.getregistry()

  • 作用:返回全局注册表(一个普通 Lua 表),用于 C 和 Lua 间共享数据。
  • 注意:直接操作注册表可能导致不可预期行为。
  • 示例
    local reg = debug.getregistry()
    reg.my_global_data = "secret"
    

7. debug.getupvalue(f, idx)

  • 作用:获取函数 f 的第 idx 个上值(闭包捕获的外部变量)的名称和值。
  • 示例
    local x = 5
    local f = function() return x + 1 end
    local name, value = debug.getupvalue(f, 1)
    print(name, value)  --> "x", 5
    

8. debug.getuservalue(u)

  • 作用:获取 userdata 或线程关联的 Lua 值。
  • 示例
    local ud = newproxy(true)  -- 创建 userdata(需Lua 5.1)
    debug.setuservalue(ud, "data")
    print(debug.getuservalue(ud))  --> "data"
    

9. debug.sethook([thread,] hook, mask [, count])

  • 作用:设置钩子函数,在指定事件(调用、返回、行执行)时触发。
  • 示例
    local function hook(event)
      print("Event:", event)
    end
    debug.sethook(hook, "crl", 2)  -- 每执行 2 条指令触发
    

10. debug.setlocal([thread,] level, idx, value)

  • 作用:修改指定堆栈帧的局部变量的值。
  • 示例
    function test()
      local a = 10
      debug.setlocal(1, 1, 20)  -- 修改第一个局部变量
      print(a)                  --> 20
    end
    test()
    

11. debug.setmetatable(value, mt)

  • 作用:强制设置值的元表,绕过 __metatable 保护。
  • 示例
    local t = {}
    setmetatable(t, { __metatable = "protected" })
    debug.setmetatable(t, { __index = { x = 1 } })
    print(t.x)  --> 1
    

12. debug.setupvalue(f, idx, value)

  • 作用:修改函数 f 的上值。
  • 示例
    local x = 5
    local f = function() return x end
    debug.setupvalue(f, 1, 10)
    print(f())  --> 10
    

13. debug.setuservalue(u, value)

  • 作用:设置 userdata 或线程的关联值。
  • 示例
    local ud = newproxy(true)
    debug.setuservalue(ud, { key = "value" })
    print(debug.getuservalue(ud).key)  --> "value"
    

14. debug.traceback([thread,] [msg [, level]])

  • 作用:生成当前堆栈跟踪的字符串,用于调试错误。
  • 示例
    function foo() error(debug.traceback("Oops")) end
    pcall(foo)  --> 输出包含堆栈跟踪的错误信息
    

15. debug.upvalueid(f, idx)

  • 作用:返回函数 f 的第 idx 个上值的唯一标识符。
  • 用途:检测两个闭包是否共享同一个上值。
  • 示例
    local x = 10
    local f1 = function() return x end
    local f2 = function() return x end
    print(debug.upvalueid(f1, 1) == debug.upvalueid(f2, 1))  --> true
    

16. debug.upvaluejoin(f1, idx1, f2, idx2)

  • 作用:让 f1 的第 idx1 个上值与 f2 的第 idx2 个上值共享。
  • 示例
    local x, y = 1, 2
    local f1 = function() return x end
    local f2 = function() return y end
    debug.upvaluejoin(f1, 1, f2, 1)  -- 共享上值
    x = 100
    print(f2())  --> 100(因为 y 的上值已与 x 绑定)
    

总结

  • 调试核心getinfogetlocalsetupvalue 用于检查或修改运行时状态。
  • 钩子机制sethookgethook 用于监控程序执行流。
  • 元表和注册表getmetatablesetmetatablegetregistry 操作底层数据。
  • 注意事项
    • 生产环境慎用 debug 库,可能引发性能或安全问题。
    • 修改运行时状态(如 setlocal)需谨慎,易导致不可预测行为。
    • 部分函数(如 upvaluejoin)适用于高级场景,需深入理解闭包机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值