Чтение таблиц Lua из аргументов в C - неверный уровень стека? - PullRequest
1 голос
/ 04 сентября 2011

Простая версия состоит в том, что я ожидаю, что мой метод __tostring, который я встроил в C, выведет "glxy_object (100)" при печати объекта в Lua. Это прекрасно работает, если я закомментирую код между комментариями «код проблемы» (биты, которые читают данные таблицы из метода 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)

Я урезал / скомбинировал базу кода для удобства чтения.

1 Ответ

3 голосов
/ 04 сентября 2011

Проблема с «кодом неисправности» находится на первом после строки комментарии: 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) где-нибудь после кода неисправности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...