C API中奇怪的lua push/pop行为

3

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

void test_pushing_and_popping(lua_State *lua) {
    printf("### STARTING PUSHING/POPPING TEST ###\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("Popped integer: %llx\n", popped_integer);
    printf("Popped float: %f\n", popped_float);
    lua_dump_stack(lua);
    printf("Asserting equality... ");
    assert(popped_integer == popped_float);
    printf("OK!\n");
    printf("Wiping the stack...\n");
    lua_settop(lua, 0);
    lua_dump_stack(lua);
    printf("### PUSHING/POPPING TEST ENDED ###\n");
}

我期望这段代码能够成功运行,并且断言会被通过,因为相同的值使用 lua_pushinteger, lua_pushnumber, lua_tointeger, 以及 lua_tonumber 分别进行了推入和弹出。

实际上,如果我在 Windows 上以 32位 的二进制形式运行该代码,它能够正常工作:

### STARTING PUSHING/POPPING TEST ###
Dumping the lua stack...
Stack element count: 0
Popped integer: 206d7578
Popped float: 544044408.000000
Dumping the lua stack...
Stack element count: 2
1       number  0x206D7578
2       number  0x206D7578
Asserting equality... OK!
Wiping the stack...
Dumping the lua stack...
Stack element count: 0
### PUSHING/POPPING TEST ENDED ###

Linux 上,以 64 位 二进制文件的形式也可以正常工作。

然而,这是在我的目标平台上的输出结果:

### STARTING PUSHING/POPPING TEST ###
Dumping the lua stack...
Stack element count: 0
Popped integer: 8002b2bc00e3a9ac <-- Wrong!
Popped float: 544044416.000000   <-- Wrong!
Dumping the lua stack...
Stack element count: 2
1   number 0x80000000 <-- Wrong!
2   number 0x206d7580 <-- Wrong!
Asserting equality... <-- Crash (assertion fail)!

什么?第一个值完全错误,即使第二个值也是错误的。544044416.000000转换为十六进制是0x206d7580,这也与推送的值0x206D7578不相等。这种不准确来自哪里? 我非常确定没有破坏任何东西,因为我在初始化lua后立即运行了测试。
printf("Initializing lua...\n");
lua = luaL_newstate(); /* Opens Lua */
luaL_openlibs(lua); /* Opens the standard libraries */
test_pushing_and_popping(lua);

有人知道问题可能是什么吗?

2
你确定 popped_integer 是一个 unsigned long longpopped_number 是一个 double 吗?如果不是,你正在使用错误的 printf 代码。 - user253751
很好的注释,定义如下: #define LUA_NUMBER float #define LUA_INTEGER int - BullyWiiPlaza
所以换句话说,"popped_integer" 不是一个 "unsigned long long","popped_number" 也不是一个 "double"?这就是为什么有些人建议避免使用 "printf",而只使用 "cout" 的原因。 - user253751
没错,我使用了-DLUA_32BITS,否则它就无法编译。 - BullyWiiPlaza
1
现在你知道了一个问题。 - user253751
1个回答

1

我最初遇到的编译错误的措辞如下:

#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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接