gpt4 book ai didi

你能从 lua 修改 C 结构吗?

转载 作者:行者123 更新时间:2023-12-04 09:46:14 26 4
gpt4 key购买 nike

我希望能够拥有这个 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 代码可以修改其变量?

最佳答案

标准 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_indexMyStruct_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 用户数据比它指向的对象存活时间长,就会导致未定义行为!

关于你能从 lua 修改 C 结构吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62095922/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com