For clarity and simplicity I will shorten the following numbers as follows:
−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
as 170…727
These numbers represent the minimum and maximum values of an 128–bit signed integer (__int128 in gcc
).
I implemented user–defined literals (raw literals) for this data type since gcc doesn’t offer a way of defining constants of this type: _u128
for unsigned __int128
and _i128
for __int128
.
The minus character is not part of the UDL, but a unary minus operator applied to the result of the UDL.
So for a -ddddd_i128
(where d
is a digit) the UDL computes a signed __int128
with the positive value ddddd
and then the compiler will apply the unary minus operator to it. So far so good.
The problem is with -170…128_i128
(which should be a valid value for __int128
):
the UDL computes the signed __int128
positive number 170…128
which is just outside of the range of __int128
, resulting in Undefined Behavior (signed integer overflow).
Any solution to represent this number constant with a UDL?
My UDL’s are declared (just a non-constexpr, loopy version for now) (they are raw literals):
unsigned __int128 operator"" _u128(char const *str);
__int128 operator"" _i128(char const *str);
Some usages:
1000000000000000000000000000000000_i128
-1000000000000000000000000000000000_i128
-170141183460469231731687303715884105728_i128 // <-- this has UB
170141183460469231731687303715884105727_u128
340282366920938463463374607431768211455_u128
I know that there are ways of defining the constant -170…728
with various ways, like bit shifts, mathematical operations, but I want to be able to create it in a consistent way, e.g. I don’t want this situation: you can create any constant using this UDL, except for -170…728_i128
, for which you have to use extra tricks.
This is essentially the same problem that implementors have when implementing <limits.h>
: INT_MIN
cannot be defined (on a typical 32-bit system) as -2147483648
. It can be (and commonly is) defined as (-2147483647 - 1)
instead. You'll have to do something similar. There may not be any way to represent the most negative number with a single negation operator and literal, but that's okay: there is simply no need for it.