Richard Heathfield said:
jacob navia said: [...]
what is clearly not
enough space to store 65521 objects of size 65552
each. You are free to call that "multiplication that
doesn't overflow".
The Standard says it doesn't overflow, and therefore it doesn't overflow
(unless the Standard is wrong, which is something you can take up with ISO
if you like, but I don't rate your chances).
[...]
You're both arguing about the meaning of the word "overflow", which is
IMHO less important than the actual behavior of integer types.
Multiplication of two values of type size_t (or of any unsigned
integer type) can yield a mathematical result that cannot be
represented as a value of type size_t. The standard does not call
this "overflow", but in my opinion "overflow" *would* be a valid term
for it.
The point is this: If a result of an unsigned multiplication cannot be
represented, the result is reduced modulo 2**N (where the maximum
value of the type is 2**N-1 -- "**" denotes exponentiation). If the
result of a signed multiplication cannot be represented, the behavior
is undefined.
Using an unsigned type as the parameter of malloc() means that a
larger range of arguments can be used than if it took the
corresponding signed type. This can be significant for systems with a
16-bit size_t that can allocate more than 32767 bytes, or for systems
with a 32-bit size-t that can allocate more than 2147483647 bytes.
jacob's argument is that using a signed type for the parameter of a
malloc-like function is beneficial, supposedly because if a user
incorrectly passes a very large value as the argument, it is likely to
wrap around to a negative value, which can be detected as an error.
In fact, the standard does not guarantee any such thing. Signed
overflow for an arithmetic operation invokes undefined behavior.
Overflow on conversion to a signed type yields an
implementation-defined result (or, in C99, raises an
implementation-defined signal).
Wraparound to a possibly negative value is not uncommon. However, the
result is just as likely to be positive (and still incorrect). Using
a signed type might catch *some* errors, but in my opinion it's not a
good solution. Unsigned types are tricky; that can't be changed
without changing the language. The only real solution is for the
*programmer* to avoid overflow in the first place, and choosing any
particular type as the parameter to a malloc-like function can't help
much with that. You might as well use size_t for consistency with the
standard library.
At times, it would be very nice to be able to define some different
behavior for unsigned "overflow" (i.e., for operations that yield a
mathematical value outside the range of the type). If I multiply two
unsigned values and get an out-of-range result, the result reduced
modulo 2**N *might* be what I want, but more often it's an error that
I'd like to know about. Ditto for signed and floating-point. But C
doesn't let us do that, at least not portably.