This won't work: if T
and T2
are unsigned, b < 0
will always be false.
Since both of these types are unsigned, it is guaranteed that overflow causes wrap around (side note: if these were signed types, overflowing would cause UB, although it usually wraps around too). Thus, you can use something like:
T a = ...;
T2 b = a;
if ((T) b != a) {
/* didn't fit */
}
else { ... }
The cast around b
is not strictly necessary: if sizeof(T)
> sizeof(T2)
, then the usual arithmetic conversions cause b
to be converted to T
before comparing to a
. However, to make it clear, I chose to explicitly leave it there.
According to section 6.3.1.3 on C99 (see comments below), this is what happens when an unsigned integer is converted to a narrower unsigned type:
if the new type is unsigned, the value is converted by repeatedly
adding or subtracting one more than the maximum value that can be
represented in the new type until the value is in the range of the new
type
This means that in case of overflow, b
will not be equal to a
when converted back to T
. That's the rationale behind this code. Moreover, it will be less than a
, so you can switch !=
to <
if you prefer.
Alternatively, you can check before assigning to b
to make sure it will fit:
T a = ...;
T2 b;
if (a > (T2)-1) {
/* won't fit */
}
else {
/* fits */
}
(T2) -1
is the maximum value that the unsigned type T2
can hold. If a
is greater than this, then it won't obviously fit into b
. To see why (T2) -1
is portable and always work, see this question: Is it safe to use -1 to set all bits to true?