我面临的这个问题涉及两个部分:
将任意结构从 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/