【问题标题】:Is there any way to programmatically determine in C/C++ how many parameters a Lua function expects?有什么方法可以在 C/C++ 中以编程方式确定 Lua 函数需要多少参数?
【发布时间】:2010-10-21 13:48:58
【问题描述】:

有没有办法在从 C/C++ 代码调用 Lua 函数之前确定它需要多少参数?

我查看了lua_Debuglua_getinfo,但它们似乎无法满足我的需求。

这似乎有点违背 Lua 的精神,但我真的想证明我在 Lua 和 C++ 之间的接口。当从 Lua 代码调用 C++ 函数时,接口会验证 Lua 提供了正确数量的参数以及每个参数的类型是否正确。如果发现参数有问题,则会发出lua_error

我希望反过来进行类似的错误检查。当 C++ 调用 Lua 函数时,它至少应该检查 Lua 函数没有声明过多的参数。

【问题讨论】:

    标签: c++ lua


    【解决方案1】:

    你所要求的在 Lua 中是不可能的。

    您可以使用一组参数定义一个 Lua 函数,如下所示:

    function f(a, b, c)
       body
    end
    

    但是,Lua 对传递给此函数的参数数量没有任何限制。

    这是有效的:

    f(1,2,3,4,5)
    

    多余的参数会被忽略。

    这也是有效的:

    f(1)
    

    剩余的参数被赋值为“nil”。

    最后,您可以定义一个接受可变数量参数的函数:

    function f(a, ...)
    

    此时您可以向函数传递任意数量的参数。

    请参阅Lua reference manual 的第 2.5.9 节。

    您可以在这里做的最好的事情是向您的 Lua 函数添​​加检查,以验证您收到了您期望的参数。

    【讨论】:

    • 好吧,我确实说过我知道我在做的事情不符合 Lua 的精神 :) 函数完全在 Lua 中实现和调用,它会按照你说的方式工作,但是我想要的是一种方式加强 Lua/C++ 接口。当您使用 Lua 函数(使用我们的自定义 Lua/C++ 绑定系统)实现 C++ 接口时,自动强制从 C++ 调用的 Lua 函数实现正确数量的参数是有意义的。也就是说,我怀疑不可能做我想做的事。以为我会问同样的问题!
    【解决方案2】:

    在 Lua 5.2 中,您可以通过使用'u' 类型填充nups, nparams, isvararg fields by get_info() 来确定参数的数量、上值以及函数是否接受可变数量的参数。此功能在 Lua 5.1 中不可用。

    【讨论】:

      【解决方案3】:

      除非您完全控制要验证的 Lua 代码,否则我不会在 Lua 方面这样做。 Lua 函数通过忽略额外的参数来忽略它们是很常见的。

      一个例子是当我们不想实现一些方法,而使用一个存根函数:

      function do_nothing() end
      
      full_api = {}
      function full_api:callback(a1, a2) print(a1, a2) end
      
      lazy_impl = {}
      lazy_impl.callback = do_nothing
      

      这允许通过重用可用函数来节省打字(和一点性能)。

      如果你仍然想做函数参数验证,你必须静态分析代码。执行此操作的一种工具是Metalua

      【讨论】:

      • 谢谢。我要去看看metalua。就我而言,Lua 代码的静态分析实际上可能比尝试在运行时进行检查要好。
      • 不客气。如果您这样做,请在 Metalua 的邮件列表 (lists.luaforge.net/mailman/listinfo/metalua-list) 中留言。您可能会从 Metalua 作者那里得到一些宝贵的建议。
      【解决方案4】:

      不,不在标准 Lua 中。并且是 Aaron Saarela 所说的,据我所知,这有点超出了 Lua 的精神。 Lua 方法是确保函数本身将 nil 视为合理的默认值(或在第一次使用之前将其转换为类似 name = name or "Bruce" 的合理默认值),或者如果没有合理的默认值,该函数应该要么抛出错误或返回失败(if not name then error"Name required" end 是前者的常用习语,if not name then return nil, "name required" end 是后者的常用习语)。通过让 Lua 方负责自己的参数检查,无论函数是从 Lua 还是 C 调用,您都可以获得这种好处。

      也就是说,您的模块可能会维护一个按函数索引的属性表,其中包含您需要知道的信息。当然,它需要维护。 MetaLua 也有可能用于添加一些语法糖,以便在编译时直接从函数声明中创建表。在调用 Lua 函数之前,您可以直接使用它来查找任何可用的属性并使用它们来验证调用。

      如果您担心防弹,您可能希望控制函数环境以谨慎使用 Lua 端可用的全局变量(如果有),并使用 lua_pcall() 而不是 lua_call() 以便你会发现任何抛出的错误。

      【讨论】:

        【解决方案5】:

        您要求的信息并非在所有情况下都可用。例如,一个 Lua 函数实际上可能在 C 中实现为 lua_CFunction。从 Lua 代码中无法区分纯 Lua 函数和 lua_CFunction。而在 lua_CFunction 的情况下,参数的数量根本不会暴露,因为它完全取决于函数的实现方式。

        另一方面,您可以做的是为函数编写者(无论是纯 Lua 还是 C 语言)提供一个系统,以告知他们的函数需要多少参数。在创建函数 (function f(a, b, c) end) 后,他们只需将其传递给全局函数 (register(f, 3))。然后,您将能够从您的 C++ 代码中检索该信息,并且如果该函数没有公布其参数,则回退到您现在所拥有的。使用这样的系统,您甚至可以宣传参数所期望的类型。

        【讨论】:

        • 你提出了一些好的观点。尽管您在第 2 段中提出的系统与默认情况一样容易出现人为错误,例如,在正常情况下,您必须依靠编码器来获得正确的参数,而在第二种情况下,编码器需要正确处理两者参数和参数元数据。
        猜你喜欢
        • 2013-06-07
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        • 2010-11-27
        • 2010-12-25
        • 2012-09-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多