从 C 中的参数读取 Lua 表 - 堆栈级别不正确?

发布于 2024-12-02 21:29:22 字数 3606 浏览 1 评论 0原文

简单的版本是,当我在 Lua 中打印对象时,我希望在 C 中内置的 __tostring 方法输出“glxy_object(100)”。如果我注释掉“问题代码”注释之间的代码(从 new() 方法读取表数据的位),它会完美地完成此操作。显然,我没有将堆栈返回到它需要去的地方,但我盯着这段代码太久了,看不出错误在哪里。

ma​​in.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;
}

ma​​in.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

厌倦 2024-12-09 21:29:22

“问题代码”的问题在于注释行后的第一行: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 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文