lua-users home
lua-l archive

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

It was thus said that the Great Mooffie once stated:
> Compiler warnings when dealing with huge integers
> This question pertains to Lua 5.1 and Lua 5.2 only, which always store
> numbers are doubles by default (in contrast to Lua 5.3).
> A project I'm contributing to gets compiled with -Wfloat-conversion
> and -Wbad-function-cast (and I can't change this). The compiler is
> gcc.
> In a C function I need to get a huge integer (a file offset, for
> example) from Lua. So I do:
>     off_t a = lua_tonumber(L, -1);
> But since lua_tonumber returns a float (double, to be exact), and
> because of -Wfloat-conversion, the above line generates a warning:
>     " warning: conversion to 'off_t {aka long long int}' from
>      'lua_Number {aka double}' may alter its value [-Wfloat-conversion] "
> (BTW, I can't use lua_tointeger because lua_Integer is typically small
> (32 bits) and I don't want to ship a copy of Lua (with a bigger
> lua_Integer) with the project.)
> On the other hand, if I write that line as:
>   off_t a = (off_t)lua_tonumber(L, -1);
> I inhibit that warning but get a different one because of the
> -Wbad-function-cast:
>     " warning: cast from function call of type 'lua_Number {aka double}'
>       to non-matching type 'long long int' [-Wbad-function-cast] "
> Is there an obvious way to get around this problem? That is, a way to
> write code that doesn't trigger these warnings?
> I know I can solve this problem by doing instead:
>     lua_Number num = lua_tonumber(L, -1);
>     off_t a = (off_t) num;
> or by defining a function encapsulating this (say,
> get_lua_huge_integer() returning a int64_t), but I was wondering if
> there's something obvious I'm missing.

  First issue---is this a 32-bit or 64-bit system?  In a 32-bit system,
values can exceed the normal signed range of -2147483648 .. 2147483647 and
the unsigned range of 0 .. 4294967295.  In a 64-bit system, things get ...
wonky when the value exceeds 9007199254740992---you'll get "gaps" in values
up to 9223372036854775807 (signed 64-bit) or 18446744073709551615 (unsigned
64-bit).  Past that, I'm not sure what you'll get (could be 0, could be
something else).

  First off, a 64-bit integer can store values in two ranges:

	-9223372036854775808 ..  9223372036854775807
	                   0 .. 18446744073709551615

A double can "safely" store integers in the range:

	   -9007199254740992 ..     9007199254740992

I say "safely" because past that range, integers start having "gaps" between
successive values (first every other number, then every fourth number, then
every eights, etc).  And what happens when you cast a double that exceeds
the range of a 64-bit value in a 64-bit value is left (I believe)
unspecified (or it's undefined---I'm not entirely sure).  The safest course
is to check that the result (as a double) fits in the "safe" range and if
not, do something sensible per the project.

  -spc (The compiler is telling you, "thar be dragons ... ")