本文内容和Lua代码无关,只是写了一段用于调试的C代码,可以使代码阅读的难度降低。只要在每个函数体的第一句写上:DEBUGFLAG。就可以通过Lua脚本控制每个函数的调试行为。调试行为包含断点、printf函数名和fprintf函数名。只需一个flag,不需要对原有的代码进行过多的修改。如:
int main()
{
DEBUGFLAG
return 0;
}
就会得到:
main{
}
输出的函数名带有缩进格式,并用花括号表示函数体。这样的格式可以很清晰的看到函数之间的调用关系。下面是
lua.c中的调用关系。
main{
pmain{
collectargs{
}
handle_luainit{
}
runargs{
}
handle_script{
getargs{
}
docall{
}
report{
}
}
}
finalreport{
}
}
通过lua脚本控制每个函数的调试行为,以下是控制lua.c的lua脚本,建立这样的脚本很简单, 函数的名称可以在VS2012的类视图中批量复制粘贴,不需要一个个的输入。
--act: 1 assert, 2 printf, 3 fprintf
funcTable =
{
dbg_collectargs = 2
,dbg_docall = 2
,dbg_dofile = 2
,dbg_dolibrary = 2
,dbg_dostring = 2
,dbg_dotty = 2
,dbg_finalreport = 2
,dbg_get_prompt = 2
,dbg_getargs = 2
,dbg_handle_luainit = 2
,dbg_handle_script = 2
,dbg_incomplete = 2
,dbg_l_message = 2
,dbg_l_sin = 2
,dbg_laction = 2
,dbg_loadline = 2
,dbg_lstop = 2
,dbg_main = 2
,dbg_pmain = 2
,dbg_print_usage = 2
,dbg_print_version = 2
,dbg_pushline = 2
,dbg_report = 2
,dbg_runargs = 2
,dbg_stackDump = 2
}
for key, value in pairs(funcTable) do
funcTable[key] = 3
end
为了更加容易区分,每个函数都以"dbg_"打头。Action函数实现了逻辑处理,在lua脚本中查找这个函数名的value,根据value的值,决定返回是assert或者输出到文本。我没有直接在Action中进行assert,因为这会使每次断点的位置都发生在Action中,有点麻烦。g_callStackIndex用于记录当前栈的深度,深度反映到输出结果就是函数名前面的空格。
//act: 1 assert, 2 printf, 3 fprintf
int Action(const char *funName)
{
if(Debug_GL == NULL)InitGL();
char tname[100];
sprintf(tname, "dbg_%s", funName);
lua_getfield(Debug_GL, -1, tname);
if(!lua_isnumber(Debug_GL, -1))
{
return 0;
}
int act = lua_tointeger(Debug_GL, -1);
lua_pop(Debug_GL, 1);
if(act == 1) ;
else if(act == 2)
{
for(int i = 0; i < g_callStackIndex; i ++)
printf(" ");
printf("%s{\n", funName);
}
else if(act == 3)
{
for(int i = 0; i < g_callStackIndex; i ++)
fprintf(Debug_fp, " ");
fprintf(Debug_fp, "%s{\n", funName);
}
return act;
}