我希望能够有以下Lua代码:
function myfunc(s)
print(s.value)
s.value = 7
end
它应该与此C(++)代码一起工作:
struct MyStruct {
float value;
};
void func() {
MyStruct var;
var.value = 5;
lua_getglobal(L, "myfunc");
// push `var` to lua, somehow
lua_call(L, 1, 0); // prints "5"
// now, var.value is 7
assert(var.value == 7);
}
我将如何推入var
堆栈,以便lua代码可以修改其变量?
Standard Lua没有内置的方法可以struct
通过表公开s的内容,因此这样做是手动过程。这是一个完整程序的示例,可以满足您的需求:
#include <assert.h>
#include <string.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
struct MyStruct {
float value;
};
int MyStruct_index(lua_State *L) {
struct MyStruct *t = (struct MyStruct *)luaL_checkudata(L, 1, "MyStruct");
const char *k = luaL_checkstring(L, 2);
if(!strcmp(k, "value")) {
lua_pushnumber(L, t->value);
} else {
lua_pushnil(L);
}
return 1;
}
int MyStruct_newindex(lua_State *L) {
struct MyStruct *t = (struct MyStruct *)luaL_checkudata(L, 1, "MyStruct");
const char *k = luaL_checkstring(L, 2);
if(!strcmp(k, "value")) {
t->value = luaL_checknumber(L, 3);
return 0;
} else {
return luaL_argerror(L, 2,
lua_pushfstring(L, "invalid option '%s'", k));
}
}
struct MyStruct *MyStruct_new(lua_State *L) {
struct MyStruct *var = (struct MyStruct *)lua_newuserdata(L, sizeof *var);
luaL_setmetatable(L, "MyStruct");
return var;
}
void func(lua_State *L) {
// Since this is allocated inside of Lua, it will be garbage collected,
// so we don't need to worry about freeing it
struct MyStruct *var = MyStruct_new(L);
var->value = 5;
lua_getglobal(L, "myfunc");
lua_pushvalue(L, -2); // push `var` to lua, somehow
lua_call(L, 1, 0); // prints "5"
// now, var->value is 7
assert(var->value == 7);
}
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// One-time setup that needs to happen before you first call MyStruct_new
luaL_newmetatable(L, "MyStruct");
lua_pushcfunction(L, MyStruct_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, MyStruct_newindex);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_dostring(L, "function myfunc(s) print(s.value) s.value = 7 end");
func(L);
lua_close(L);
return 0;
}
要支持更多字段,您必须将其添加到MyStruct_index
和中MyStruct_newindex
。如果要pairs
进行处理,则还需要添加一种__pairs
元方法。通常,尽管如此,通常更喜欢公开getter和setter方法。
如果您想struct MyStruct
在Lua之外分配您的位置,则可以在使用它的任何地方添加一个额外的间接层,如下所示:
#include <assert.h>
#include <string.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
struct MyStruct {
float value;
};
int MyStruct_index(lua_State *L) {
struct MyStruct **t = (struct MyStruct **)luaL_checkudata(L, 1, "MyStruct");
const char *k = luaL_checkstring(L, 2);
if(!strcmp(k, "value")) {
lua_pushnumber(L, (*t)->value);
} else {
lua_pushnil(L);
}
return 1;
}
int MyStruct_newindex(lua_State *L) {
struct MyStruct **t = (struct MyStruct **)luaL_checkudata(L, 1, "MyStruct");
const char *k = luaL_checkstring(L, 2);
if(!strcmp(k, "value")) {
(*t)->value = luaL_checknumber(L, 3);
return 0;
} else {
return luaL_argerror(L, 2,
lua_pushfstring(L, "invalid option '%s'", k));
}
}
void MyStruct_push(lua_State *L, struct MyStruct *var) {
struct MyStruct **t = (struct MyStruct **)lua_newuserdata(L, sizeof *t);
*t = var;
luaL_setmetatable(L, "MyStruct");
}
void func(lua_State *L) {
struct MyStruct var;
var.value = 5;
lua_getglobal(L, "myfunc");
MyStruct_push(L, &var); // push `var` to lua, somehow
lua_call(L, 1, 0); // prints "5"
// now, var.value is 7
assert(var.value == 7);
// WARNING! `var` is about to go out of scope! If Lua uses the userdata
// that references it beyond this point, it's Undefined Behavior! Make
// sure that it didn't keep a copy of it!
}
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// One-time setup that needs to happen before you first call MyStruct_new
luaL_newmetatable(L, "MyStruct");
lua_pushcfunction(L, MyStruct_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, MyStruct_newindex);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_dostring(L, "function myfunc(s) print(s.value) s.value = 7 end");
func(L);
lua_close(L);
return 0;
}
但这很危险!如果Lua用户数据的寿命超过了它所指向的对象,则将导致未定义行为!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句