C++ Lua userdata messing with Mathfu float values

我试着使用Lua中的Mathfu::Vector创建向量,但是在尝试从堆栈中检索用户数据时出现了问题。

以下是我用于定义用户数据的函数

static int vec4(lua_State *L)
{
  const float x = luaL_checknumber(L, 1);
  const float y = luaL_checknumber(L, 2);
  const float z = luaL_checknumber(L, 3);
  const float w = luaL_checknumber(L, 4);

  mathfu::Vector<float, 4> vec(x, y, z, w);
  *static_cast<mathfu::Vector<float, 4> **>(
      lua_newuserdata(L, sizeof(mathfu::Vector<float, 4> *))) = &vec;
  luaL_setmetatable(L, VECTOR_LIB_NAME);

  return 1;
}

我有一个函数,根据 self 值和一个参数 (都是用户数据) 来获取两个向量的点积

static int dotVector(lua_State *L)
{
  mathfu::Vector<float, 4> *vecA = *static_cast<mathfu::Vector<float, 4> **>(luaL_checkudata(L, 1, VECTOR_LIB_NAME));
  mathfu::Vector<float, 4> *vecB = *static_cast<mathfu::Vector<float, 4> **>(luaL_checkudata(L, 2, VECTOR_LIB_NAME));

  LOGI("A: %f, %f, %f", vecA->x, vecA->y, vecA->z);
  LOGI("B: %f, %f, %f", vecB->x, vecB->y, vecB->z);
  float dot = mathfu::Vector<float, 4>::DotProduct(*vecA, *vecB);
  lua_pushnumber(L, dot);

  return 1;
};

在lua中调用如下

local vecA = vec4(1, 2, 3, 4)
local vecB = vec4(5, 6, 7, 8)
vecA:dot(vecB)

但是打印出来的值像是将错误的数据转换为浮点数

A: -8055257885499399810754615288266752.000000, 0.000000, 0.000000
B: 0.000000, 3746318080.000000, 3573.204346

我检查了堆栈,前两个元素肯定是UserData,但我似乎无法深入挖掘用户数据。C++变量包含那些值,但我想知道是什么原因导致这种情况。我非常确定用户数据不是我期望的在我期望的地方。

点赞
用户871617
用户871617

最后发现这只是一个愚蠢的错误,使用&获取对象的指针似乎是不正确的方式。我将我的向量初始化代码更改为:

static int vec4(lua_State *L)
{
  const float x = luaL_checknumber(L, 1);
  const float y = luaL_checknumber(L, 2);
  const float z = luaL_checknumber(L, 3);
  const float w = luaL_checknumber(L, 4);

  *static_cast<mathfu::Vector<float, 4> **>(
      lua_newuserdata(L, sizeof(mathfu::Vector<float, 4> *))) = new mathfu::Vector<float, 4>(x, y, z, w);;
  luaL_setmetatable(L, VECTOR_LIB_NAME);

  return 1;
}

现在一切都正常工作了,我认为这是因为当我使用new时,它会给我一个“实际”的指针地址,而不是一个引用?吃一堑,长一智。

2020-02-18 16:16:36
用户5637254
用户5637254

不,你出现了内存泄漏。第一个版本是指向栈分配对象的指针(&vec),它在函数结束时被销毁。

第二个版本(new mathfu::Vector)在堆上正确创建...我猜您后来从未将其删除=内存泄漏。

此外,尝试避免指针的static_cast。或者任何强制转换。这将会增加问题,例如,如果 g++ 使用“strict-aliasing”(隐含的 -O3)则任何指针转换都会崩溃。 "strict-aliasing" 假设一个内存块从不被不同类型的指针引用。或者您应该明确地配置编译器以避免这种情况。

通用的好主意是使用 memcpy。编译器正确理解并优化它。例如,如果您想要将指针作为 char 转换为 int32:

int32 a;
char b[sizeof(a)];
memcpy(b, &a, sizeof(a));

现在使用 b 代替

static_cast<char*>(&a);
2020-02-18 16:45:27