Библиотека C OpenBSD имеет расширение под названием reallocarray(3), которое делает realloc(array, size*nmemb)
без взрыва, если умножение переполняется. Реализация содержит этот фрагмент:
/*
* 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))
На сайте Programmers.SE модифицированная версия этого расчета была отклонена за техническую некорректность. 4
, очевидно, должно быть CHAR_BIT/2
, но это не единственная проблема. Предположим необычный ABI, в котором size_t
имеет биты заполнения. (Это не до смешного неправдоподобно: рассмотрим микроконтроллер с 32-битными регистрами, но 24-битным адресным пространством.) Тогда SIZE_MAX
меньше, чем 1 << (sizeof(size_t)*CHAR_BIT)
[в арифметике с бесконечной точностью], и вычисление неверно.
Итак, вопрос: можете ли вы вычислить floor(sqrt(SIZE_MAX+1))
, используя только арифметику целочисленного константного выражения C99, не делая никаких предположений о ABI, кроме того, что требует C99, плюс то, что вы можете узнать из <limits.h>
? Обратите внимание, что SIZE_MAX
может равняться UINTMAX_MAX
, т. е. не может быть никакого типа, который может представлять SIZE_MAX+1
без переполнения.
EDIT: я думаю, что SIZE_MAX
должно быть 2n 1 для некоторого положительного целого числа n, но не обязательно в форме 22n 1 рассмотрим S/390, один из ABI которого имеет 31-битное адресное пространство. Поэтому: Если sqrt(SIZE_MAX+1)
не является целым числом, желаемый результат (учитывая, как используется эта константа) составляет floor()
от истинного значения.
MUL_NO_OVERFLOW
является степенью двойки? - person zch   schedule 02.09.2014SIZE_MAX+1
является степенью двойки, а2¹⁶ ≤ SIZE_MAX
≤ 2⁶⁴? Если это так, это будет означать, что существует не более 49 возможных значений, и можно использовать оператор?:
, чтобы выбрать одно из них. Используя некоторые вложенные макросы, соответствующее выражение может быть достаточно кратко выражено в исходном коде. - person supercat   schedule 02.09.2014_MAX
форму 2^N-1 для некоторого N, но у меня нет моей копии стандарта на этом компьютере. - person zwol   schedule 02.09.2014SIZE_MAX
было 2^31-1. - person zwol   schedule 02.09.2014#define M SIZE_MAX #define S2 1.41421... #define MUL_NO_OVERFLOW (size_t) ((((M&1)?S2:1) * ((M&2)?2.0:1) * ((M&4)?2.0*S2:1) * ((M&16)?4.0:1) ... ) + 0.0001)
. - person chux - Reinstate Monica   schedule 02.09.2014#define X ((int) (1.5*1.5))
, для формированияint y[X];
? - person chux - Reinstate Monica   schedule 02.09.2014SIZE_MAX == power(2,n)-1
, а затем#if SIZE_MAX == 65535 #define MUL_NO_OVERFLOW 256 #else if SIZE_MAX == 131072 #define MUL_NO_OVERFLOW 362 #else if SIZE_MAX == 262144 #define MUL_NO_OVERFLOW 512 ... #endif
? (Имейте случай для каждого (16 ‹= n ‹= 64 или 128) Нет баллов за элегантность, но, похоже, работа выполнена. - person chux - Reinstate Monica   schedule 02.09.2014(nmemb >= SIZE_MAX/256 || size >= 256)
, минуя всю проблему квадратного корня. - person zch   schedule 03.09.2014