快速掌握Lua 5.3 —— 调试库 (1)

来源:互联网 发布:vmware14安装ubuntu 编辑:程序博客网 时间:2024/06/07 12:19

Q:什么是活动函数?

A:程序中被调用但还未执行完成的函数。

function g()    --[[ 此时函数"g"被调用但还未执行完成,是活动函数。所以这里获取的是函数"g"的信息。         "debug.getinfo(2)"获取的才是函数"f"的信息。]]    local x = debug.getinfo(1, "n")    for k, v in pairs(x) do         print(k, v)    end endfunction f()    -- 此时函数"f"被调用但还未执行完成,是活动函数。所以这里获取的是函数"f"的信息。    local x = debug.getinfo(1, "n")    for k, v in pairs(x) do         print(k, v)    end     print()    g()endf()--[[ result:      namewhat        global     name    f     namewhat        global     name    g]]

Q:什么是调用栈?

A:Lua存储活动函数所使用的栈。每个线程都有自己独立的调用栈。

Q:什么是调用栈的级别?

A:调用调试库函数的函数的栈级别是1,调用该函数的函数的栈级别是2,以此类推。

function foo()    -- 调用调试库的函数。    ...endfunction goo()    foo()endfunction hoo()    goo()end--[[ 被调用的调试库函数栈级别为0,"foo"的栈级别为1,"goo"的栈级别为2,"hoo"的栈级别为3。     如果还有别的函数调用"hoo()",则栈级别以此类推。]]hoo()    

Q:如何查看调用栈信息?

A:

--[[ debug.traceback([thread,] [message [, level]])     首先打印"message",接着从第"level"个栈级别开始打印"thread"线程中的调用栈信息。     如果"message"不是字符串或"nil",则函数不做任何处理直接返回"message""thread"默认为当前线程,"level"默认为1。]]function foo()    print(debug.traceback("This is traceback: "))    print()    print(debug.traceback("Traceback from stack_level 2: ", 2))    print()    print(debug.traceback({}))endfunction goo()    foo()endfunction hoo()    goo()endhoo()--[[ results:      This is traceback:      stack traceback:             E:\a.lua:2: in function 'foo'             E:\a.lua:8: in function 'goo'             E:\a.lua:12: in function 'hoo'             E:\a.lua:15: in main chunk             [C]: in ?     Traceback from stack_level 2:      stack traceback:             E:\a.lua:8: in function 'goo'             E:\a.lua:12: in function 'hoo'             E:\a.lua:15: in main chunk             [C]: in ?     table: 00522F78]]

Q:如何查看函数信息?

A:

--[[ debug.getinfo([thread,] f [, what])     返回一个"table",其中包含线程"thread"中的函数"f""what"指定的相关信息。     "thread"默认为当前线程。"f"可以是函数名,也可以是一个数值,如果是数值则代表该函数的栈级别。     如果通过名字指定的函数不存在,则报错;如果通过数值指定的函数不存在,则返回"nil"。     如果"what"不指定,默认情况下返回除合法行号表外的所有域:         source: 创建这个函数的"chunk"的名字。                  如果"source"'@'打头,表示这个函数定义在一个文件中,而'@'之后的部分就是文件名。                 若"source"'='打头,表示之后的部分由用户行为来决定如何表示源码。                 其它的情况下,这个函数定义在一个字符串中,而"source"正是那个字符串。         short_src: 一个“可打印版本”的"source",用于出错信息。         linedefined: 函数定义开始处的行号。         lastlinedefined: 函数定义结束处的行号。         what: 如果函数是一个Lua函数,则为一个字符串"Lua";               如果是一个C函数,则为"C";               如果是一个"chunk"的主体部分,则为"main"。         currentline: 给定函数正在执行的那一行。当提供不了行号信息的时候,"currentline"被设为-1。         name: 给定函数的一个合理的名字。               因为Lua中的函数是"first-class values",所以它们没有固定的名字。               一些函数可能是全局复合变量的值,另一些可能仅仅只是被保存在一个"table"的某个域中。               Lua会检查函数是怎样被调用的,以此来找到一个适合的名字。               如果它找不到名字,该域就被设置为"NULL"。         namewhat: 用于解释"name"域。                   其值可以是"global""local""method""field""upvalue",或是"",                   这取决于函数怎样被调用。(Lua用空串表示其它选项都不符合)         istailcall: 如果函数以尾调用形式调用,这个值为"true"。在这种情况下,当前栈级别的调用者不在栈中。         nups: 函数的"upvalue"个数。         nparams: 函数固定形参个数(对于C函数永远是0)。         isvararg: 如果函数是一个可变参数函数则为"true"(对于C函数永远为"true")。         func: 函数本身。         activelines: 合法行号表。                      表中的整数索引用于描述函数中哪些行是有效行。                      有效行指有实际代码的行,即你可以置入断点的行。无效行包括空行和只有注释的行。     "what"可以指定如下参数,以指定返回值"table"中包含上面所有域中的哪些域:         'n': 包含"name""namewhat"域;         'S': 包含"source""short_src""linedefined""lastlinedefined"以及"what"域;         'l': 包含"currentline"域;         't': 包含"istailcall"域;         'u': 包含"nup""nparams"以及"isvararg"域;         'f': 包含"func"域;         'L': 包含"activelines"域;]]-- 简易版"debug.traceback()"。function traceback()    local level = 1    while true do        local info = debug.getinfo(level, "Sl")        if not info then break end        if info.what == "C" then     -- is a C function?            print(level, "C function")        else     -- a Lua function            print(string.format("[%s]:%d", info.short_src, info.currentline))        end        level = level + 1    endend

Q:如何调试函数局部变量信息?

A:

--[[ debug.getlocal([thread,] f, local)     返回在线程"thread"中栈级别为"f"处函数的索引为"local"的局部变量的名字和值。     "thread"默认为当前线程。此函数不仅用于访问显式定义的局部变量,也包括形参、临时变量等。     函数"f"中第一个形参或是定义的第一个局部变量的索引为1,然后遵循在代码中定义的顺序索引值递增,     只计算函数当前作用域中的活动变量。     负索引代表可变参数。-1指第一个可变参数,以此类推。如果指定的"local"处没有变量,则返回"nil"。     如果指定的"f"越界,则报错。(你可以调用"debug.getinfo()"来检查栈级别是否合法)     以'('开头的变量名表示没有名字的变量(比如是循环控制用到的控制变量,或是去除了调试信息的代码块)。     "f"也可以是一个函数。这种情况下,此函数仅能返回"f"形参的名字。]]function foo(a, b)    -- 1, 2    local x    -- 3    do local c = a - b end    -- "c"的作用范围只在"do-end"之间,所以不会在函数"foo"中被计数。    local a = 1    -- 4    while true do        local name, value = debug.getlocal(1, a)    -- 这里的"a"是上面"local a = 1"的"a"。        if not name then break end        print(name, value)        a = a + 1    -- 索引+1,下一个变量。    endendfoo(10, 20)--[[ result:      a       10     b       20     x       nil     a       4]]print()for i = 1, 4 do     print(debug.getlocal(foo, i))    -- 提供函数名字,只能打印其形参。end--[[ result:      a     b     nil     nil]]--[[ debug.setlocal([thread,] level, local, value)     与"debug.getlocal()"的功能相对,     将"value"赋给"thread"线程中栈级别为"level"处函数的索引为"local"的局部变量。     "thread"默认为当前线程。"level"只能指定为栈级别,而不能指定为函数名称。     关于索引以及异常返回值,参见"debug.getlocal"函数。     如果执行成功,函数返回局部变量的名字。]]function foo(a, b)    -- 1, 2    local x    -- 3    do local c = a - b end    -- "c"的作用范围只在"do-end"之间,所以不会在函数"foo"中被计数。    local a = 1    -- 4    print(debug.getlocal(1, 1))    -- a    10    debug.setlocal(1, 1, 50)    print(debug.getlocal(1, 1))    -- a    50endfoo(10, 20)

Q:如何调试”metatable”信息?

A:

--[[ debug.getmetatable(value)     返回"value"的"metatable",若"value"没有"metatable"则返回"nil"。     debug.setmetatable(value, table)     将"value"的"metatable"设置为"table"(可以为"nil"),函数返回"value"。]]local t1 = {__index = function (table, key)        return "metatable 1"    end}local t2 = {__index = function (table, key)        return "metatable 2"    end}local t = {}setmetatable(t, t1)print(t1, debug.getmetatable(t))    --> table: 00802C50    table: 00802C50debug.setmetatable(t, t2)print(t2, debug.getmetatable(t))    --> table: 00802D60    table: 00802D60

Q:如何调试”userdata”信息?

A:

--[[ debug.getuservalue(u)     返回关联在"u"上的Lua值。如果"u"不是"userdata",则返回"nil"。     debug.setuservalue(udata, value)     将"value"设置为"udata"的关联值。"udata"必须是一个"full userdata"。]]

附加:

1、尽可能只在调试过程中使用调试库中的函数。首先,库中一些函数的性能并不卓越。其次,它打破了Lua语言中一些基本的规则,比如函数中定义的局部变量无法在其外部被访问。最后,你一定不希望在你的最终产品中见到它的身影,所以你可以使用,debug = nil来剔除调试库,同时减少最终产品的大小。
2、debug.getinfo()对于”Tail Calls”,只将被包裹函数计入栈级别的计算,包裹函数不计入,

function g()    local x = debug.getinfo(1)    -- 这里获取的是函数"g"的信息。函数"f"不计入栈级别的计算。    for k, v in pairs(x) do         print(k, v)    end endfunction f()    return g()endf()

所以要查看”Tail Calls”的包裹函数信息,请直接指定函数名。

0 0
原创粉丝点击