lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


David Given wrote:
> float delta = [positive or negative number];
> unsigned int x = x + (unsigned int) delta;
> 
> I was finding that on one platform (Intel) the sprites moved in both
> directions. On another platform (ARM) the sprites would only move to the
> right. Turns out that on ARM, casting a negative float to an unsigned
> int produces 0, which on Intel it's equivalent to casting it to a signed
> int.
> 
> And they're *both* right --- you're allowed either interpretation. (The
> game had been written for Intel, and was wrong.)

Ouch. I guess this would then affect Lua 5.1.4, too. See line 785
of lstrlib.c:

  sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));

This is casting a double to an uint32_t or uint64_t. Which got me
thinking why both of these lines work fine:

  assert(string.format("%x", -1) == "ffffffff")
  assert(string.format("%x", 0xffffffff) == "ffffffff")

Remember that for lua_Number = double, 0xffffffff turns into
4294967295, which is not a legal int32_t. And -1 is not a legal
uint32_t. But both are common arguments for "%x" I guess.

I found out this is actually a side-effect of how GCC and MSVC
cast doubles to uint32_t on x87: by going via an int64_t and then
taking the least-significant 32 bits. I.e. this cannot be relied
upon.

One might get away with always defining LUA_USELONGLONG and
casting first to signed then to unsigned INTFRM_T. But I'm not
sure this is the best fix. And it needs to be adapted for MSVC,
too (non-standard MS stuff: "I64" and __int64).

--Mike