C API 中奇怪的 lua 压入和弹出行为

我注意到在我的目标平台上(32 位 PowerPC 架构),使用 C API 在 lua 中将值推入和弹出堆栈的行为非常奇怪。考虑以下测试函数:

void test_pushing_and_popping(lua_State *lua) {
    printf("### 开始推入 / 弹出测试 ###\n");
    lua_dump_stack(lua);
    const auto value = static_cast<uint32_t>(0x206D7578);
    lua_pushinteger(lua, value);
    lua_pushnumber(lua, value);
    const auto popped_integer = lua_tointeger(lua, 1);
    const auto popped_float = lua_tonumber(lua, 2);
    printf("弹出的整数:%llx\n", popped_integer);
    printf("弹出的浮点数:%f\n", popped_float);
    lua_dump_stack(lua);
    printf("断言相等... ");
    assert(popped_integer == popped_float);
    printf("成功!\n");
    printf("清空堆栈...\n");
    lua_settop(lua, 0);
    lua_dump_stack(lua);
    printf("### 推入 / 弹出测试结束 ###\n");
}

我期望这段代码能够成功运行,并且由于相同的值被使用 lua_pushinteger、lua_pushnumber、lua_tointeger 以及 lua_tonumber 分别推入和弹出,所以断言应该也能通过。

的确,如果我将代码作为 32 位二进制文件在 Windows 上运行,它是成功的:

### 开始推入 / 弹出测试 ###
Dumping the lua stack...
Stack element count: 0
弹出的整数:206d7578
弹出的浮点数:544044408.000000
Dumping the lua stack...
Stack element count: 2
1       number  0x206D7578
2       number  0x206D7578
断言相等... 成功!
清空堆栈...
Dumping the lua stack...
Stack element count: 0
### 推入 / 弹出测试结束 ###

在 64 位的 Linux 二进制文件上也可以成功。

然而,在我的目标平台上,它的输出如下所示:

### 开始推入 / 弹出测试 ###
Dumping the lua stack...
Stack element count: 0
弹出的整数:8002b2bc00e3a9ac <-- 错误的值!
弹出的浮点数:544044416.000000   <-- 错误的值!
Dumping the lua stack...
Stack element count: 2
1   number 0x80000000 <-- 错误的值!
2   number 0x206d7580 <-- 错误的值!
断言相等... <-- 崩溃(断言失败)!

什么?第一个值完全错误,甚至第二个值也是错误的。544044416.000000 转换为十六进制是 0x206d7580,也不等于推入的值 0x206D7578。这个误差从哪里来的?

我非常确定我没有破坏任何东西,因为我在初始化 lua 之后立即运行测试:

printf("初始化 lua...\n");
lua = luaL_newstate(); /* Opens Lua */
luaL_openlibs(lua); /* Opens the standard libraries */
test_pushing_and_popping(lua);

有人知道是什么问题吗?

点赞
用户3764804
用户3764804

起初我遇到的编译错误如下所述:

#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
  or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"

结果我使用了 -DLUA_32BITS 编译标志,导致数据类型大小过小:

#define LUA_INTEGER int
#define LUA_NUMBER float

使用最大可能的数据类型是正确的方法,可以通过标志 -DLUA_C89_NUMBERS 来实现。

这将定义数据类型如下:

#define LUA_INTEGER long
#define LUA_NUMBER double
2020-07-28 14:54:50