Для ясности и простоты я сокращу следующие числа следующим образом:
−170,141,183,460,469,231,731,687,303,715,884,105,728
как -170…728
170,141,183,460,469,231,731,687,303,715,884,105,727
как 170…727
Эти числа представляют минимальное и максимальное значения 128-разрядного целого числа со знаком (__int128 в gcc
).
Я реализовал пользовательские литералы (необработанные литералы) для этого типа данных, поскольку gcc не предлагает способ определения констант этого типа: _u128
за unsigned __int128
а также _i128
за __int128
,
Символ минус не является частью UDL, но унарный оператор минус применяется к результату UDL.
Так что для -ddddd_i128
(где d
является цифрой) UDL вычисляет подписанный __int128
с положительным значением ddddd
и тогда компилятор применит к нему унарный оператор минус. Все идет нормально.
Проблема с -170…128_i128
(которое должно быть действительным значением для __int128
):
UDL вычисляет подписанный __int128
положительное число 170…128
который находится за пределами диапазона __int128
, что приводит к неопределенному поведению (целочисленное переполнение со знаком).
Любое решение для представления этой числовой константы с UDL?
Мои UDL объявлены (просто не constexpr, чокнутый версия на данный момент) (они необработанные литералы):
unsigned __int128 operator"" _u128(char const *str);
__int128 operator"" _i128(char const *str);
Некоторые использования:
1000000000000000000000000000000000_i128
-1000000000000000000000000000000000_i128
-170141183460469231731687303715884105728_i128 // <-- this has UB
170141183460469231731687303715884105727_u128
340282366920938463463374607431768211455_u128
Я знаю, что есть способы определения постоянной -170…728
с различными способами, такими как битовые сдвиги, математические операции, но я хочу иметь возможность создавать его согласованным образом, например, Я не хочу этой ситуации: вы можете создать любую константу, используя этот UDL, кроме -170…728_i128
, для которого вы должны использовать дополнительные трюки.
По сути, это та же проблема, что и у разработчиков <limits.h>
: INT_MIN
не может быть определено (в типичной 32-битной системе) как -2147483648
, Это может быть (и обычно) определяется как (-2147483647 - 1)
вместо. Вам придется сделать что-то подобное. Может не быть никакого способа представить наиболее отрицательное число одним оператором отрицания и литералом, но это нормально: в этом просто нет необходимости.