当我使用 SWIG 生成 varargs 函数的包装器时,它会插入代码来检查传递给函数的参数的确切数量,例如给出的:
%inline %{
void foobar(const char *fmt, ...) {}
生成的包装器始终插入:
SWIG_check_num_args("foobar",1,1)
如何解决这个问题并允许任意数量的参数大于或等于 1?
最佳答案
可以解决这个问题,并生成使用一系列技巧传递额外参数时不会出错的代码。
本质上,黑客行为归结为这一观察 - 在 SWIG_check_num_args
调用之前我们唯一可以控制的是局部变量的声明和初始化。然而,我们可以利用这一点来创建一个隐藏全局变量的局部变量,并据此改变行为。
%module test
%runtime %{
static inline int SWIG_check_num_args_real(lua_State* L, const char *fn, int min_args, int max_args) {
SWIG_check_num_args(fn, min_args, max_args);
return 1;
fail:
return 0;
}
#undef SWIG_check_num_args
#define SWIG_check_num_args(name,a,b) if (!SWIG_check_num_args_real(L,name,a,_global_is_varargs?1024:b)) goto fail;
static const int _global_is_varargs=0;
%}
%typemap(in) (const char *fmt, ...) (const int _global_is_varargs=1) %{
$typemap(in,const char *) // Default string stuff
// TODO: Do some real work with the rest of the arguments here
%}
%inline %{
void foobar(const char *fmt, ...) {}
void boring(int i) {}
%}
为了使这一概念发挥作用,我们需要插入一些代码,用我们控制的宏替换默认宏 SWIG_check_num_args
,理想情况下无需完全重写宏,以防万一以后发生变化。为此,我们设置了一个内联函数,以便为宏命中另一个 fail
标签,但可以在稍后的 #undef
之前应用宏的原始定义.
有了该内联函数,我们就可以将宏重新定义为稍微更有利的宏,它使用一个名为 _global_is_varargs
的变量来动态修改宏的第三个参数,并在我们“处于一种 varargs 的情况。 (1024 完全是任意的,INT_MAX 或某些特定于实现的限制同样有效)。
我们计划隐藏的变量需要以魔术前缀 _global_
开头,以避免 automatic appending of a suffix onto local variable names 。由于一切都是 const,智能编译器可能可以做到这一点,而无需额外的运行时开销。
然后我们可以编写类型映射来实际创建一个局部变量来屏蔽全局变量并对 Lua 参数做一些实际的工作。在我的示例中,我将其作为多参数类型映射来执行,但这可能不是绝对必要的。 (无论如何,我喜欢完全匹配)。
有了这个,我们就可以按预期调用函数(尽管它没有做任何有用的事情,这是预处理器/FFI/ABI/gcc 扩展乐趣的练习):
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> m=require('test')
> m.boring()
stdin:1: Error in boring expected 1..1 args, got 0
stack traceback:
[C]: in function 'test.boring'
stdin:1: in main chunk
[C]: in ?
> m.boring(1)
> m.foobar()
stdin:1: Error in foobar expected 1..1024 args, got 0
stack traceback:
[C]: in function 'test.foobar'
stdin:1: in main chunk
[C]: in ?
> m.foobar('')
> m.foobar('',1)
> m.foobar('',1,2,3)
它不会破坏正常的检查,并且仍然对函数调用参数强制执行一些合理的操作。
关于lua - 强制 SWIG 生成 Lua 包装器以允许 varargs 函数使用额外参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50686021/