Andre Majorel <ch****@hallibu rton.comwrites:
How do you compute an off_t with overflow detection ?
There is no off_t type defined in the standard C library. But IMHO
your question is still topical.
More generally, given a type off_t (a typedef for some signed integer
type, defined in some implementation-specific header), how can you do
computations in that type with overflow detection?
That's a fairly tricky question, especially if you don't have OFF_MIN
and OFF_MAX macros specifying the lower and upper bounds.
[...]
Overflow-safe versions of + and * would do but not even a
relatively recent standard like SUS v2 provides OFF_MIN and
OFF_MAX and since off_t is a signed integer type, overflows lead
to undefined behaviour.
What are we supposed to do ? Compare sizeof (off_t) with sizeof
(int/long/long long[1]) and use INT_MAX/LONG_MAX/LLONG_MAX[1] ?
Carry the calculation with doubles, cast to off_t and cast back
to double for verification[2] ? Use bignum ?
If I wanted portability, I wouldn't use double. For example, if both
off_t and double are 64 bits, double won't be able to represent all
values of type off_t (it wastes bits on that silly exponent thingie);
long double might, but there's no guarantee that *any* floating-point
type can represent all values of a given integer type.
I don't think there's any 100% portable way to determine the bounds.
You can probably get away with comparing sizeof(off_t) to sizeof(int),
etc.; if you find a type whose size matches, you can *assume* that its
bounds are the same as those of that type. It's not impossible that
that assumption will break if there are padding bits. (I think that
Cray vector machines have padding bits for some integer types; I'll
check the details later, when I get a chance).
Or you might have a system-specific header that defines OFF_MIN and
OFF_MAX, with a requirement that the header be modified for each
target system.
Once you've done that, you can check the values of the operands before
performing the operation. For (x + y):
If the signs differ, or either operand is zero, you're ok.
If both operands are positive and x <= OFF_MAX - y, you're ok.
If both operands are negative and (...), you're ok.
Otherwise, the operation will overflow.
The "(...)" above is left as an exercise (I'm too lazy to work it out).
Multiplication is similar but more complicated. Subtraction is
addition using the negation of one of the operands. Division can
overflow only in the case of OFF_MIN / -1, and only if OFF_MIN <
-OFF_MAX.
This is going to slow things down quite a lot.
An implementation is free to define the behavior of integer overflow.
If your implementation does so, and you don't mind losing portability,
you can take advantage of that. On many implementations , overflow
quietly wraps around; you can check the result against the operands
rather than pre-checking the operands. For example, if both operands
are positive and the result does not exceed both operands, you had an
overflow. Multiplication is trickier.
--
Keith Thompson (The_Other_Keit h)
ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.