简单的版本是我希望我在C中构建的__tostring方法在Lua中打印对象时输出“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)
为了便于阅读,我修剪/组合了我的代码库。
答案 0 :(得分:3)
“故障代码”的问题出现在评论后面的第一行: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)
。