how to find out the type of userdata when Lua calling C/C++

747 Views Asked by At

I'm using Lua to call a dll file. my c/c++ code is like this:

#include <iostream>
extern "C"{
    #include "lua.hpp"
    #include "lualib.h"
    #include "lauxlib.h"
}

using namespace std;

typedef struct StructA{
    int a;
} structA;

typedef struct StructB{
    char *b;
} structB;

static int createA(lua_State *L)
{
    int n = lua_gettop(L);
    size_t iBytes = sizeof(struct StructA);
    struct StructA *sa;
    sa = (StructA *)lua_newuserdata(L, iBytes);
    sa->a = 1;
    return 1;
}

static int createB(lua_State *L)
{
    int n = lua_gettop(L);
    size_t iBytes = sizeof(struct StructB);
    struct StructB *sb;
    sb = (StructB *)lua_newuserdata(L, iBytes);
    sb->b = "2";
    return 1;
}

static int print(lua_State *L)
{
    if("some condition")//struct type is StructA
    {
        cout<< "struct type is StructA" <<endl;
        struct StructA *sa = (struct StructA *)lua_touserdata(L, 1);
        cout<< "a:"<<(sa->a) <<endl;
    }else if("some condition")//struct type is structB
    {
        cout<< "struct type is StructB" <<endl;
        struct StructB *sb = (struct StructB *)lua_touserdata(L, 1);
        cout<< "b:"<<(sb->b) <<endl;
    }
    return 0;
}

static luaL_Reg mylibs[] = {
    { "A", createA },
    { "B", createB },
    { "print", print },
    { NULL, NULL }
};



extern "C" __declspec(dllexport)
int luaopen_occi_test(lua_State* L)
{
    luaL_register(L, "occi_test", mylibs);
    return 1;
}

and I used VS2010 to compile this C/C++ code. My Lua code is like this:

local a = occi_test.A()
local b = occi_test.B()
occi_test.print(a)
occi_test.print(b)

as you can see,in Lua,parameter a and b are both userdata type,but in C/C++,a's type is StructA,b's type is StrcutB,so when Lua calling a C/C++ function and passing a or b,how C/C++ code find out the paramter's type?Please complete this code by replace "some condition" by something can do the job.

1

There are 1 best solutions below

0
On
  1. At the beginning of luaopen_occi_test, do luaL_newmetatable(L, "StructA"); and luaL_newmetatable(L, "StructB");. This will add metatables to the registry that you can use later.
  2. At the end of createA and createB, do luaL_setmetatable(L, "StructA"); and luaL_setmetatable(L, "StructB");. This will attach the appropriate metatable you created in step 1 to the new userdata objects.
  3. For your conditions in print, use luaL_testudata(L, 1, "StructA") and luaL_testudata(L, 1, "StructB"). These return a pointer to the userdata (which is true when converted to a Boolean) when it's a userdata with the named metatable, or a null pointer (which is false when converted to a Boolean) otherwise. Alternatively, you could slightly optimize the code by saving the results and then using just the right one, like this:
static int print(lua_State *L)
{
    struct StructA *sa;
    struct StructB *sb;
    if((sa = (struct StructA *)luaL_testudata(L, 1, "StructA")) != nullptr)
    {
        cout<< "struct type is StructA" <<endl;
        cout<< "a:"<<(sa->a) <<endl;
    }else if((sb = (struct StructB *)luaL_testudata(L, 1, "StructB")) != nullptr)
    {
        cout<< "struct type is StructB" <<endl;
        cout<< "b:"<<(sb->b) <<endl;
    }
    return 0;
}