2 Stimmen

Lua-Tabelle(n) aus Args in C lesen - falsche Stack-Ebene?

Die einfache Version ist, dass ich erwarte, dass meine __tostring-Methode, die ich in C gebaut habe, "glxy_object(100)" ausgibt, wenn ich das Objekt in Lua drucke. Dies geschieht perfekt, wenn ich den Code zwischen den "Problemcode"-Kommentaren auskommentiere (die Bits, die die Tabellendaten von der new()-Methode einlesen). Offensichtlich bringe ich den Stack nicht dorthin zurück, wo er hingehört, aber ich habe zu lange auf diesen Code gestarrt, um zu erkennen, wo der Fehler liegt.

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)

Stromausgabe

new() - id: 100 - position: (1.00, 2.00, 3.00), rotation: (4.00, 5.00, 6.00)
table: 0x7fe702510b70

erwartete Ausgabe / Ausgabe beim Auskommentieren von 'trouble code' (abzüglich falscher pos/rot-Werte)

new() - id: 100 - position: (0.00, 0.00, 0.00), rotation: (0.00, 0.00, 0.00)
glxy_object(100)

Ich habe meine Code-Basis auf Lesbarkeit getrimmt/zusammengefasst.

3voto

sbk Punkte 8872

Das Problem mit "trouble code" ist der Kommentar in der ersten Zeile: lua_pop(L, 1); . Dadurch werden die neu erstellten Benutzerdaten so angezeigt glxy_object_new gibt am Ende seinen zweiten Parameter zurück und nicht den erstellten glxy_object .

Es gibt zwei schnelle Möglichkeiten, dies zu beheben. Die erste ist das Entfernen der lua_pop(L, 1); Zeile und ändern Sie die beiden Zeilen im Fehlercode, die besagen lua_gettable(L, -2); a lua_gettable(L, -3) . Die zweite ist die Hinzufügung einer weiteren lua_pushuserdata(L, o) irgendwo nach dem Fehlercode.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X