Для ясности и простоты я буду сокращать следующие числа следующим образом:
−170,141,183,460,469,231,731,687,303,715,884,105,728
as-170…728
170,141,183,460,469,231,731,687,303,715,884,105,727
as170…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, loopy) (это необработанные литералы):
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
, для которой приходится использовать дополнительные приемы.
-2147483648
(в системе, где int 32 бита), это UB? 05.08.20142147483648
будет иметь типlong long
, поэтому выражение не имеет предполагаемого значения. FWIW, версияlong long
(обычно-9223372036854775808
) недействительна. Не неопределенное поведение, но если нет целочисленного типа со знаком, который может содержать9223372036854775808
, то использование9223372036854775808
всегда будет ошибкой. 05.08.2014-2147483648
не буквальный. Это выражение, состоящее из литерала2147483648
с примененным к нему унарным оператором-
. Унарный-
может переполниться. 05.08.2014