【问题标题】:Handling Lua calls and errors in C in a bulletproof way以防弹的方式处理 C 中的 Lua 调用和错误
【发布时间】:2015-02-19 13:39:49
【问题描述】:

我在 Lua 电子设备模拟插件上工作。
我想让它在设计和可用性方面做得很好,因为很可能很多用户都远离 IT 和调试。
用户在 Lua 中描述设备,插件通过 Lua C API 进行翻译。
用户可能会拼错函数名称、变量类型和参数顺序。
好的手册会有所帮助,但应用程序不应崩溃或提供错误描述的错误。我没有找到任何“最佳实践”并想询问有经验的用户,因为我对 Lua 还很陌生。

参数的顺序和类型

目前 Lua 函数是这样声明的:

typedef struct lua_bind_func
{
    int32_t ( *lua_c_api ) ( lua_State* );
    const char* lua_func_name;
} lua_bind_func;

然后

{.lua_func_name="state_to_string", .lua_c_api=&lua_state_to_string},

为了检查参数顺序和类型是否正确传递:

创建宏:

#define STRING (&lua_isstring)
#define INT (&lua_isinteger)
#define USER (&lua_islightuserdata)

将数组添加到列表中:

int ( *args[16] ) ( lua_State*, int index );

更改功能列表:

{.lua_func_name="set_callback", .lua_c_api=&lua_set_callback, .args={INT, INT}}

参数列表检查器:

static void
SAFE_EXECUTE ( lua_State* L, void* curfunc )
{
    int argnum = lua_gettop ( L );
    for ( int i=0; lua_c_api_list[i].lua_func_name; i++ )
    {
        if ( curfunc == lua_c_api_list[i].lua_c_api )
        {
            for ( int argcount=0; lua_c_api_list[i].args[argcount]; argcount++ )
            {
                if ( argnum < argcount+1 )
                {
                    IDSIMMODEL* model = ( IDSIMMODEL* ) lua_get_model_obj ( L );
                    print_error ( model, "Too few arguments passed to the function \"%s\"", lua_c_api_list[i].lua_func_name );
                }
                else if ( !lua_c_api_list[i].args[argcount] ( L, argcount+1 ) )
                {
                    IDSIMMODEL* model = ( IDSIMMODEL* ) lua_get_model_obj ( L );
                    print_error ( model, "Argument %d is of wrong type", argcount+1 );
                }
            }
        }
    }
}

然后我可以检查参数顺序,它们的类型,并可以通过迷你帮助创建相应的错误消息:

SAFE_EXECUTE ( L, &lua_set_callback );

代码不处理额外的参数,但很容易添加。
问题:是否可以,或者可能有更好的方案?

函数名称拼写错误

例如我有以下代码:

set_callback(time + 100 * MSEC, PC_EVENT)   
set_calback(time + 200 * MSEC, PC_EVENT)
set_callback(time + 333 * MSEC, PC_EVENT)   

第二个拼写错误,在这部分之后没有执行任何代码。
我不明白如何在 C 中捕获对未定义函数的调用以引发足够的错误。

其他陷阱

也许还有更多我不知道的潜在陷阱?

【问题讨论】:

  • 通常你只需通过调用 lua 的 API 提供的 lua_check* 来检查在 lua_CFunction 函数本身中传入的参数。目前尚不清楚为什么您需要将它们放入链接列表中。如果您需要更多地控制 lua 脚本的执行方式,pcallxpcall 之类的函数在这里会有所帮助。你也可以使用 lua-tables 模拟 python 的关键字参数参数,在这种情况下,参数顺序并不重要。
  • 原因是为了更直观,每次检查都只是单行循环检查。但是桌子的想法很有趣。你能把它作为一个问题来回答吗?
  • 如果您发布显示您如何检查参数以及如何调用底层 C 函数的绑定代码,这可能会有所帮助。另请注意,您不需要创建自己的 lua_bind_func 结构,lua-api 已经提供了类似的东西——它被称为 luaL_Reg
  • 我更新了问题。是的,它会降低性能,但这可以在脚本中禁用。它仅用于调试目的

标签: c design-patterns error-handling lua lua-api


【解决方案1】:

要使用 Lua 运行调用 C 函数的脚本,您需要:

  • 使用 Lua 协议编写每个要导出到 Lua 的 C 函数,以获取参数和返回值。
  • 将这些 C 函数作为全局变量或表中的字段导出到 Lua。
  • 运行您的用户脚本来捕捉语法错误和执行错误, 使用受保护的调用。
  • 可选择为用户脚本提供解析全局变量的环境。

C API 提供了无需太多工作即可完成所有这些工作的函数。

查看 Lua 源代码中包含的标准 C 库。从最简单的开始,例如 mathos

阅读本书Programming in Lua

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2016-10-21
    • 2016-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多