c - 将任意结构从 C 传递到 LUA 并访问它

标签 c variables struct lua arguments

我面临的这个问题涉及两个部分:

  1. 将任意结构从 C 传递到 Lua 函数。例如,考虑这两个结构:

    struct Person{
      int age;
      char *name;
    };
    
    struct Paper{
      int width;
      int height;
      char *color;
    };
    

    我希望能够使用简单的 C 函数将它们传递给 Lua,例如:

    template<class T>
    void call(T t){
       ...  (pseudo-code)
    
      check t:
         if Person, lua_getglobal(L, "sendPerson")
         if Paper, lua_getglobal(L, "sendPaper")
    
      for each element in t, check its type
         if integer, lua_pushinteger(...)
         if char*, lua_pushstring(...)
      ...
    
      lua_pcall(...)
    }
    
    Person p = {33, "David"};
    Paper A4 = {210, 297, "white"};
    call(p);
    call(A4);
    

    2) 访问它。在 Lua 端,如何通过名称访问这些变量?

    function sendPerson(p)
        print(p.age)
        print(p.name)
    end
    
    function sendPaper(p)
        print(p.width)
        print(p.height)
        print(p.color)
    end
    

    我知道我可以使用 setfield,但除非我可以在调用 Lua 函数的通用方法中调用它,否则我看不出这怎么可能。

更新:这是代码。例如,这里是 WM_LBUTTONDOWN 事件。这样做,我需要有 2 个方法和 1 个结构来处理我发送给 lua 的消息:创建线程的第一个方法,调用 lua 函数的第二个方法,以及结构,这样我就可以将它作为参数传递给线程功能。

struct LButtonEvent{
int x, y, k;
};

LuaScript *L = new LuaScript(FILENAME);

void _onLButtonDown(LPVOID arg)
{
    LButtonEvent *b = (LButtonEvent*) arg;
    lua_State *l = L->getState();
    lua_getglobal(l, "onLButtonDown");
    lua_newtable(l);
    lua_pushinteger(l, b->x); lua_setfield(l, -2, "x");
    lua_pushinteger(l, b->y); lua_setfield(l, -2, "y");
    lua_pushinteger(l, b->k); lua_setfield(l, -2, "k");

    lua_pcall(l, 1, 0, 0);
}

void LuaScript::onLButtonDown(LButtonEvent b)
{
    // I want my window to continue proccessing messages. If lua script calls "sleep", the window freezes.
    CreateThread(0, 0, (LPTHREAD_START_ROUTINE) _onLButtonDown, (LPVOID) &b, 0, 0); 
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN:
        LButtonEvent b;
        b.x = (int)(short)LOWORD(lParam);
        b.y = (int)(short)HIWORD(lParam);
        b.k = wParam;
        L->onLButtonDown(b);
        break;

    ....
    }

    return 0;
}

最佳答案

我不会通过不同的功能来区分这两种(或更多)类型。使用元表!这样,您不需要知道确切的类型,只需使用唯一可用的函数,它就会做正确的事情。

在这里您可以看到如何做到这一点,但请记住,有更好的方法来创建和打开库。

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include <stdio.h>

int create_person(lua_State* L)
{
    int age = lua_tointeger(L, -2);
    const char* name = lua_tostring(L, -1);

    lua_newtable(L);
    lua_pushinteger(L, age);
    lua_pushstring(L, name);
    lua_setfield(L, -3, "name");
    lua_setfield(L, -2, "age");

    luaL_setmetatable(L, "personmeta");

    return 1;
}

int print_person(lua_State* L)
{
    lua_getfield(L, -1, "name");
    const char* name = lua_tostring(L, -1);
    lua_getfield(L, -2, "age");
    int age = lua_tointeger(L, -1);

    printf("Name: %s\nAge : %d\n", name, age);
    return 0;
}

int create_paper(lua_State* L)
{
    int width = lua_tointeger(L, -3);
    int height = lua_tointeger(L, -2);
    const char* color = lua_tostring(L, -1);
    lua_newtable(L);

    lua_newtable(L);
    lua_pushinteger(L, width);
    lua_pushinteger(L, height);
    lua_setfield(L, -3, "height");
    lua_setfield(L, -2, "width");

    lua_pushstring(L, color);
    lua_setfield(L, -3, "color");
    lua_setfield(L, -2, "dimensions");

    luaL_setmetatable(L, "papermeta");

    return 1;
}

int print_paper(lua_State* L)
{
    lua_getfield(L, -1, "color");
    const char* color = lua_tostring(L, -1);
    lua_getfield(L, -2, "dimensions");
    lua_getfield(L, -1, "width");
    lua_getfield(L, -2, "height");
    int height = lua_tointeger(L, -1);
    int width = lua_tointeger(L, -2);

    printf("Paper: { %d, %d, %s }\n", width, height, color);
    return 0;
}

int luaopen_llib(lua_State* L)
{
    // initialization

    // create metatable for persons
    luaL_newmetatable(L, "personmeta");
    luaL_newmetatable(L, "personmeta");
    lua_setfield(L, -2, "__index");
    lua_pushcfunction(L, print_person);
    lua_setfield(L, -2, "print");
    lua_pop(L, 1);

    // create metatable for paper
    luaL_newmetatable(L, "papermeta");
    luaL_newmetatable(L, "papermeta");
    lua_setfield(L, -2, "__index");
    lua_pushcfunction(L, print_paper);
    lua_setfield(L, -2, "print");
    lua_pop(L, 1);

    // create library table and store the creation functions
    lua_newtable(L);
    lua_pushcfunction(L, create_person);
    lua_setfield(L, -2, "create_person");
    lua_pushcfunction(L, create_paper);
    lua_setfield(L, -2, "create_paper");
    return 1;
}

用于测试的Lua代码:

local llib = require "llib"

local p = llib.create_person(33, "David")
p:print() -- Name: David 
          -- Age : 33

local paper = llib.create_paper(210, 297, "white")
paper:print() -- Paper: { 210, 297, "white" }

当然,你需要相应地命名这个库。

如果需要用到userdata,同样可以使用。用户数据可以有元表。

关于c - 将任意结构从 C 传递到 LUA 并访问它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40369986/

相关文章:

c - 如何在 C 中使用另一个结构体内部的结构体(同时使用 malloc 和 2D 数组?)

c - 转移/减少 yacc 中的冲突

javascript - 上标计算 Javascript 变量

php - "Notice: Undefined variable"、 "Notice: Undefined index"、 "Warning: Undefined array key"和 "Notice: Undefined offset"使用 PHP

php - 如何使用可变变量 PHP 在 for 循环中使用 SELECT 创建字符串

c - 在函数 : expected declaration specifiers 中传递结构体指针

c - C中的帕斯卡三角形

c - 没有 math.h 的对数计算

c - stub 特殊功能寄存器

C++ 无法将 1 写入结构成员