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.
The trouble with "trouble code" is on the first after line the comment: lua_pop(L, 1);
. This pops the newly created userdata so glxy_object_new
ends up returning its second parameter and not the created glxy_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 say lua_gettable(L, -2);
to lua_gettable(L, -3)
. The second one is to add another lua_pushuserdata(L, o)
somewhere after the trouble code.
精彩评论