Question

Let's assume I have a type name called T and its size always is >= T2 both are unsigned. How do I check if a variable a of type T will fit into T2 without overflow and if it didn't fit do some other operation? I've tried check if it's became negative but I'm not sure if it's right way to check, like this:

T a = ...;
T2 b = a;
if(b < 0) // didn't fit
else // ok, fit

No correct solution

OTHER TIPS

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?

Because T2 is unsigned, your if (b < 0) will not work. The following should be ok:

    T a = ...;
    T2 b;
    if (a > (T2)-1) // a won't fit into a T2
       //...
    else
       b = a; // safe, no overflow, value unchanged

You need -1 rather than ~0, because the latter is an int, and won't work if T2 is wider than an int. (But ~0LL will work for all the usual types.)

I believe that for an unsigned type T2, its maximum value is always (T2)-1. From the C99 standard:

6.3.1.3 Signed and unsigned integers

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

2 Otherwise, 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.49)

3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

So, for example, if the maximum value of T2 is 10, then (T2)-1 is evaluated by adding 11 to -1, to get 10, as desired.

See also Question about C behaviour for unsigned integer underflow and Is it safe to assign -1 to an unsigned int to get the max value? and Signed to unsigned conversion in C - is it always safe?.

T  a = ...;
T2 b = a;
if (b < a) // didn't fit
else // ok, fit

Just one byte away from what you wrote :-)

This works because for unsigned types an overflow always generates a smaller value, and the comparison will only convert b to T, which is unproblematic.

From the C99 standard (6.3.1.3 Signed and unsigned integers):

[...] 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 also means that the solution by Joseph Quinsey is correct: you can always compare a to (T2)-1, which is guaranteed to be the maximum value the unsigned type T2 can hold:

if (a > (T2)-1)) // won't fit

Please note that the standards never speaks of "sizes" (except when talking about sizeof), in order to remain general. Of course, the iterative procedure I cited boils down to truncating high order bits probably in all contemporary architectures, but you never know...

I've placed some pseudocode here to help. You should be able to get the answer from that pseudocode by tidying it up.

What you want to do is check all of the bits that are > the number of bits in T2. If any of them are "1", you can't store that particular T variable safely in a T2.

// If T is an int (32 bits) and T2 is a char (8 bits):
// assume variable a is the integer in question.

int mask = 0;
for (int i = sizeof(T2); i < sizeof(T); ++i)
{
    int mask = 1 << i;
    if (a & mask)
    {
        // if this hits, we have a "1" in that bit, so the value cannot fit.
        return false;
    }
    return true;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top