OpenBSD's C library has an extension called reallocarray(3) which does realloc(array, size*nmemb)
without blowing up if the multiplication overflows. The implementation contains this fragment:
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
Over on Programmers.SE a modified version of that calculation got dinged for technical incorrectness. 4
should obviously be CHAR_BIT/2
, but that's not the only problem. Suppose an unusual ABI in which size_t
has padding bits. (This is not ridiculously implausible: consider a microcontroller with 32-bit registers but a 24-bit address space.) Then SIZE_MAX
is less than 1 << (sizeof(size_t)*CHAR_BIT)
[in infinite-precision arithmetic] and the calculation is wrong.
So, question: Can you compute floor(sqrt(SIZE_MAX+1))
using only C99 integer-constant-expression arithmetic, making no assumptions whatsoever about the ABI other than what C99 requires plus what you can learn from <limits.h>
? Note that SIZE_MAX
may equal UINTMAX_MAX
, i.e. there may not be any type that can represent SIZE_MAX+1
without overflow.
EDIT: I think SIZE_MAX
is required to be 2n − 1 for some positive integer n, but is not necessarily of the form 22n − 1 — consider S/390, one of whose ABIs has a 31-bit address space. Therefore: If sqrt(SIZE_MAX+1)
is not an integer, the desired result (given how this constant is used) is floor()
of the true value.