从 C 中的参数读取 Lua 表 - 堆栈级别不正确?
简单的版本是,当我在 Lua 中打印对象时,我希望在 C 中内置的 __tostring 方法输出“glxy_object(100)”。如果我注释掉“问题代码”注释之间的代码(从 new() 方法读取表数据的位),它会完美地完成此操作。显然,我没有将堆栈返回到它需要去的地方,但我盯着这段代码太久了,看不出错误在哪里。
main.c
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
typedef struct {
double x;
double y;
double z;
} glxy_vector3;
typedef struct {
int id;
glxy_vector3 position;
glxy_vector3 rotation;
} glxy_object;
#define OBJNAME "glxy_object"
static int glxy_object_new(lua_State *L) {
int n = lua_gettop(L);
if (n != 2)
return luaL_error(L, "Got %d arguments expected 2", n);
size_t nbytes = sizeof(glxy_object);
glxy_object *o = (glxy_object *)lua_newuserdata(L, nbytes);
luaL_getmetatable(L, OBJNAME);
lua_setmetatable(L, -2);
// id
o->id = luaL_checknumber(L, 1);
// TROUBLE CODE
lua_pop(L, 1);
lua_pushstring(L, "position");
lua_gettable(L, -2);
lua_getfield(L, -1, "x");
o->position.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "y");
o->position.y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "z");
o->position.z = lua_tonumber(L, -1);
lua_pop(L, 2);
lua_pushstring(L, "rotation");
lua_gettable(L, -2);
lua_getfield(L, -1, "x");
o->rotation.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "y");
o->rotation.y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "z");
o->rotation.z = lua_tonumber(L, -1);
lua_pop(L, 2);
// END TROUBLE CODE
// This actually prints the data just fine, so I am reading it correctly at least...
printf("new() - id: %d - position: (%0.2f, %0.2f, %0.2f), rotation: (%0.2f, %0.2f, %0.2f)\n",
o->id, o->position.x, o->position.y, o->position.z, o->rotation.x, o->rotation.y, o->rotation.z
);
return 1;
}
static glxy_object *glxy_object_check(lua_State *L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
glxy_object *o = (glxy_object *)luaL_checkudata(L, 1, OBJNAME);
if (o == NULL) luaL_typerror(L, 1, OBJNAME);
return o;
}
static int glxy_object_tostring(lua_State *L) {
glxy_object *o = (glxy_object *)lua_touserdata(L, 1);
if (o == NULL) luaL_typerror(L, 1, OBJNAME);
lua_pushfstring(L, "glxy_object(%d)", o->id);
return 1;
}
static const struct luaL_reg glxy_object_f[] = {
{ "new", glxy_object_new },
{ NULL, NULL }
};
static const struct luaL_reg glxy_object_m[] = {
{ "__tostring", glxy_object_tostring },
{ NULL, NULL }
};
int glxy_register_object(lua_State *L) {
luaL_openlib(L, OBJNAME, glxy_object_f, 0);
luaL_newmetatable(L, OBJNAME);
luaL_openlib(L, 0, glxy_object_m, 0);
lua_pushliteral(L, "__index");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 1);
return 1;
}
int main(void) {
// setup lua
L = luaL_newstate();
luaL_openlibs(L);
// register Lua accessable C objects
glxy_register_object(L);
lua_pop(L, 1);
luaL_dofile(L, "main.lua");
return 0;
}
main.lua
local o = glxy_object.new(100, { position={ x=1.0, y=2.0, z=3.0 }, rotation={ x=4.0, y=5.0, z=6.0 } })
print(o)
当前输出
new() - id: 100 - position: (1.00, 2.00, 3.00), rotation: (4.00, 5.00, 6.00)
table: 0x7fe702510b70
注释掉“问题代码”时的预期输出/输出(减去不正确的 pos/rot 值) )
new() - id: 100 - position: (0.00, 0.00, 0.00), rotation: (0.00, 0.00, 0.00)
glxy_object(100)
我已经修剪/合并了我的代码库以提高可读性。
The simple version is that I expect my __tostring method I have built in C to output "glxy_object(100)" when I print the object in Lua. It does this perfectly if I comment out the code between the "problem code" comments (the bits that read the table data in from the new() method). Clearly I am not returning the stack to where it needs to go, but I've been staring at this code too long to see where the error is.
main.c
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
typedef struct {
double x;
double y;
double z;
} glxy_vector3;
typedef struct {
int id;
glxy_vector3 position;
glxy_vector3 rotation;
} glxy_object;
#define OBJNAME "glxy_object"
static int glxy_object_new(lua_State *L) {
int n = lua_gettop(L);
if (n != 2)
return luaL_error(L, "Got %d arguments expected 2", n);
size_t nbytes = sizeof(glxy_object);
glxy_object *o = (glxy_object *)lua_newuserdata(L, nbytes);
luaL_getmetatable(L, OBJNAME);
lua_setmetatable(L, -2);
// id
o->id = luaL_checknumber(L, 1);
// TROUBLE CODE
lua_pop(L, 1);
lua_pushstring(L, "position");
lua_gettable(L, -2);
lua_getfield(L, -1, "x");
o->position.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "y");
o->position.y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "z");
o->position.z = lua_tonumber(L, -1);
lua_pop(L, 2);
lua_pushstring(L, "rotation");
lua_gettable(L, -2);
lua_getfield(L, -1, "x");
o->rotation.x = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "y");
o->rotation.y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "z");
o->rotation.z = lua_tonumber(L, -1);
lua_pop(L, 2);
// END TROUBLE CODE
// This actually prints the data just fine, so I am reading it correctly at least...
printf("new() - id: %d - position: (%0.2f, %0.2f, %0.2f), rotation: (%0.2f, %0.2f, %0.2f)\n",
o->id, o->position.x, o->position.y, o->position.z, o->rotation.x, o->rotation.y, o->rotation.z
);
return 1;
}
static glxy_object *glxy_object_check(lua_State *L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
glxy_object *o = (glxy_object *)luaL_checkudata(L, 1, OBJNAME);
if (o == NULL) luaL_typerror(L, 1, OBJNAME);
return o;
}
static int glxy_object_tostring(lua_State *L) {
glxy_object *o = (glxy_object *)lua_touserdata(L, 1);
if (o == NULL) luaL_typerror(L, 1, OBJNAME);
lua_pushfstring(L, "glxy_object(%d)", o->id);
return 1;
}
static const struct luaL_reg glxy_object_f[] = {
{ "new", glxy_object_new },
{ NULL, NULL }
};
static const struct luaL_reg glxy_object_m[] = {
{ "__tostring", glxy_object_tostring },
{ NULL, NULL }
};
int glxy_register_object(lua_State *L) {
luaL_openlib(L, OBJNAME, glxy_object_f, 0);
luaL_newmetatable(L, OBJNAME);
luaL_openlib(L, 0, glxy_object_m, 0);
lua_pushliteral(L, "__index");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 1);
return 1;
}
int main(void) {
// setup lua
L = luaL_newstate();
luaL_openlibs(L);
// register Lua accessable C objects
glxy_register_object(L);
lua_pop(L, 1);
luaL_dofile(L, "main.lua");
return 0;
}
main.lua
local o = glxy_object.new(100, { position={ x=1.0, y=2.0, z=3.0 }, rotation={ x=4.0, y=5.0, z=6.0 } })
print(o)
current output
new() - id: 100 - position: (1.00, 2.00, 3.00), rotation: (4.00, 5.00, 6.00)
table: 0x7fe702510b70
expected output / output when commenting out 'trouble code' (minus incorrect pos/rot values)
new() - id: 100 - position: (0.00, 0.00, 0.00), rotation: (0.00, 0.00, 0.00)
glxy_object(100)
I've trimmed/combined my code base down for readability.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
“问题代码”的问题在于注释行后的第一行:
lua_pop(L, 1);
。这会弹出新创建的用户数据,因此glxy_object_new
最终返回其第二个参数,而不是创建的glxy_object
。有两种快速方法可以解决此问题。第一个是删除
lua_pop(L, 1);
行,并将故障代码中的lua_gettable(L, -2);
行更改为lua_gettable(L, -3)
。第二个是在故障代码后面的某处添加另一个 lua_pushuserdata(L, o) 。The trouble with "trouble code" is on the first after line the comment:
lua_pop(L, 1);
. This pops the newly created userdata soglxy_object_new
ends up returning its second parameter and not the createdglxy_object
.There are two quick ways to fix this. The first one is to remove the
lua_pop(L, 1);
line and change both lines in the trouble code that saylua_gettable(L, -2);
tolua_gettable(L, -3)
. The second one is to add anotherlua_pushuserdata(L, o)
somewhere after the trouble code.