**SWIG **函数返回多种类型的类型映射

编辑:

我正在尝试创建一个基于在 Lua 中使用的变量名的简单 getter 函数。

例如,可以在 Lua 中使用以下方式:

num = 123
str = "hello"
print(my.getValue("num")); -> 结果:123
print(my.getValue("str")); -> 结果:hello

这是 myBindings.h 文件

static void getValue(const char *name, lua_State *L)
{
    lua_getglobal(L, name);
    switch (lua_type(L, -1))
    {
        case LUA_TBOOLEAN:
            //返回布尔值
            break;
        case LUA_TNUMBER:
            //返回数字
            break;
        case LUA_TSTRING:
            //返回字符串
            break;
        case LUA_TTABLE:
            //返回表
            break;
        default:
            //返回空值
            break;
    }
    lua_pop(L, 1);
}

这是 myBindings.i 文件。

%module my
%{
    #include "myBindings.h"
%}

%include <stl.i>
%include <std_except.i>
%include <exception.i>
%include <typemaps.i>

%typemap(default) (lua_State *L)
{
    $1 = L;
}

%include "myBindings.h"

我应该如何创建一个 SWIG 类型映射,使 getValue 函数在 Lua 中返回不同类型的值?

点赞
用户1944004
用户1944004

getValue函数存在一个问题。在switch语句之后弹出时,会弹出在switch语句内推入的任何元素。我猜想意图是弹出类型查询的全局变量。因此,我只是将类型保存在本地变量中,并立即弹出全局变量。为了说明这个例子,我推入了一些虚拟值。

static void getValue(const char *name, lua_State *L)
{
    lua_getglobal(L, name);
    switch (lua_type(L, -1))
    {
        case LUA_TBOOLEAN:
            lua_pushboolean(L, true);
            break;
        case LUA_TNUMBER:
            lua_pushnumber(L, 3.14);
            break;
        case LUA_TSTRING:
            lua_pushstring(L, "Hello world!");
            break;
        case LUA_TTABLE:
            lua_newtable(L);
            lua_pushstring(L, "value");
            lua_setfield(L, -2, "key");
            break;
        default:
            lua_pushnil(L);
            break;
    }
    // 在返回前,我们必须清理堆栈。 
    // 目前这个顺序上有全局变量“名称”和返回值
    //
    // 1. 返回值
    // 2. “名称”
    //
    // 不能简单地使用lua_pop(L,1),因为那样会删除我们要保留的返回值。 要弹出特定位置的元素,必须使用lua_remove。
    lua_remove(L, -2);
}

界面文件看起来很好,但您必须通知SWIG,您在C ++函数中推入堆栈,并希望返回推入的内容。因此,您必须在argout typemap中增加SWIG_arg。

%module my
%{
#include "myBindings.h"
%}

%typemap(default) (lua_State *L) {
    $1 = L;
}

%typemap(argout) (lua_State *L) {
    ++SWIG_arg;
}

%include "myBindings.h"

现在我们可以检查测试脚本。在第一个案例中,我们使用“num”调用“getValue”,其中“num”具有数字类型。因此,我们期望得到3.14,因为这是C ++函数推送的内容。在第二种情况下,我们使用“str”调用,其中“str”是string类型。因此,我们应该得到“Hello world!”。

local my = require("my")

num = 123
str = "hello"
print(my.getValue("num"))
print(my.getValue("str"))

让我们试试吧!

$ swig -lua -c++ test.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2/ -fPIC -shared test_wrap.cxx -o my.so -llua5.2
$ lua5.2 test.lua
3.14
Hello world!

在问题被编辑之前的旧答案

"in" typemap是错误的。 numinputs = 0告诉SWIG,对于具有此签名的函数不需要任何输入。这是不正确的,因为name作为参数传递。但是,增加numinputs = 1会强制您自己检查和转换第一个参数。最好让SWIG处理它,并将此参数从typemap中删除。

%typemap(in, numinputs = 0) (void **p) {
    $1 = nullptr;
}

“argout” typemap毫无意义,并且甚至不是有效的C ++。即使您纠正了无效的强制转换,它仍然是一个巨大的类型不安全的内存泄漏。

2018-07-13 10:47:03