1

Possible Duplicate:
Best way to detect integer overflow in C/C++

What is the best way to detect if integer truncation occurred?
Edit
This should cause truncation being signalled but it doesn't

#include <iostream>

using std::cout;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;


int32_t my32bitInt = 0xffffffff;

int32_t tmp = my32bitInt & 0xFFFF8000;

uint16_t ss = my32bitInt;

int main()
{

    if (tmp != 0xFFFF8000 && tmp != 0x00000000)
    { // cannot be converted safely 
        cout << "truncation";
    }
        cout << ss << '\n';
    cout << my32bitInt << '\n';
    return 0;
}  

Edit 2

template <typename U, typename T>
bool is_safe(T t)
{
    return sizeof(U) <= sizeof(T) ? 
    (t >= static_cast<T>(std::numeric_limits<U>::min()))
        && (t <= static_cast<T>(std::numeric_limits<U>::max())) : true;
}    

Edit 3 (Based on Oli's <>) - I found some problems, but working on it, will update asap

template bool is_safe(Source value) {

if (sizeof(Result) == sizeof(Source))
{/*Same size*/

    if (std::is_same<Source,Result>::value)
    {
        //signed to signed or unsigned to unsigned when size is same - no problem
        return true;
    }
    else
    {
        //MSB mustn't be set in Source
        return !(value & (1u << ((sizeof(Source) * CHAR_BIT) - 1)));
    }
}
else
{//smaller to larger and larger to smaller

    if (sizeof(Result) <= sizeof(Source))
    { //Larger to smaller and both equal
        return ((value >= static_cast<Source>(std::numeric_limits<Result>::min()))
                && (value <= static_cast<Source>(std::numeric_limits<Result>::max())));
    }
    else
    { //smaller to larger

        if (std::is_signed<Source>::value && !std::is_signed<Result>::value)
        {
            //signed to unsigned - signed must be positive
            return (value >= 0);
        }
        else
        {
            return true;
        }
    }
}

}

Community
  • 1
  • 1
There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194
  • what do you mean by "truncation"? overflow? – Mat Apr 16 '11 at 09:18
  • I thought I saw this question earlier this week, but I can't find it now. – Robin Green Apr 16 '11 at 09:27
  • Maybe 'integer truncation' is integer overflow e.g. on addition. Or maybe loss of data when converting to a narrower type? – Jim Blackler Apr 16 '11 at 09:32
  • 1
    Follow up: Google is telling me that integer truncation can mean converting a fractional type to an adjacent integer, e.g. 3.21 to 3 – Jim Blackler Apr 16 '11 at 09:33
  • @All Integer truncation != integer overflow. – There is nothing we can do Apr 16 '11 at 09:39
  • 2
    Care to explain the difference, then? And what you define "integer truncation" as? Obviously people aren't sure what you mean by that. – Cody Gray - on strike Apr 16 '11 at 09:43
  • @Cody yes I care, integer truncation can occur when assigning larger type to smaller. And I would like you to note that it isn't me who "defines" as such integer truncation. – There is nothing we can do Apr 16 '11 at 09:48
  • @There: That is a type of overflow, specifically resulting from a narrowing conversion. – Potatoswatter Apr 16 '11 at 11:58
  • @Potatoswatter if truncation is a type of overflow which more precisely describes action/effect that it is more appropriate to use more precise word. So if truncation is form of overflow but overflow is not form of truncation then if you/I/one thinks about specific case (truncation) then overflow is to wide and instead truncation (word) should be used. – There is nothing we can do Apr 16 '11 at 12:03
  • @There: Except I've never heard the term "truncation" used that way. How is overflow resulting from addition *not* "truncation"? – Potatoswatter Apr 16 '11 at 12:08
  • 1
    From Wikipedia: "In mathematics and computer science, truncation is the term for limiting the number of digits right of the decimal point, by discarding the least significant ones." – Potatoswatter Apr 16 '11 at 12:09
  • When using signed numbers 0xFFFFFFFF is the same as -1, which can be converted to a smaller signed value. Hence, the code is correct. (Well, as long as you assume the signed integers are represented using two-complement. In general, try to avoid mixing signed integers and bit operations.) – Lindydancer Apr 16 '11 at 12:24
  • @all_voters_to_close WHAT'S WRONG WITH THIS Q? – There is nothing we can do Apr 16 '11 at 15:16

5 Answers5

4

See Boost Numeric Conversion, specifically numeric_cast.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
1

You can check that the value is the same after the assignment.

smallInt = largeInt;

if (smallInt != largeInt)
{
  // Truncation
}

Or, you could check with a mask before:

if (my32bitInt & 0xFFFF0000)
{
  // Can't be assigned to a 16 bit value.
}
Lindydancer
  • 25,428
  • 4
  • 49
  • 68
0

I'm not a C++ programmer but i think you should do something like this:

#include <iostream.h>

int main()
{

    float number = 0.001;
    if ((int) number == number)
    {

        cout << "Hello world";
    }
    return 0;
}

Hope that is a correct solution.

Rob
  • 45,296
  • 24
  • 122
  • 150
Anton Petrov
  • 684
  • 5
  • 14
  • 1
    I can't see any good reason (length of code, copyright on code, etc) to have the code not be in the answer, so I've copied it into the answer. – Rob Apr 16 '11 at 14:36
  • Thank u! It's just that i've already had written it there, cause i didn't have a compiler on my machine :D. – Anton Petrov Apr 18 '11 at 10:30
0

If you want to check without doing the conversion, in a type-safe manner, how about the following:

template <typename U, typename T>
bool is_safe(T t)
{
    return (t >= (T)std::numeric_limits<U>::min())
        && (t <= (T)std::numeric_limits<U>::max());
}

int main()
{
    int32_t a = -32768;
    int32_t b = +32768;
    int32_t c = +32767;
    int32_t d = -32769;
    std::cout << is_safe<int16_t>(a) << std::endl;  // 1
    std::cout << is_safe<int16_t>(b) << std::endl;  // 0
    std::cout << is_safe<int16_t>(c) << std::endl;  // 1
    std::cout << is_safe<int16_t>(d) << std::endl;  // 0
}

Obviously this will break if U is a bigger type than T, but I'm sure it could be adapted.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • what about this ... check my edit. – There is nothing we can do Apr 16 '11 at 11:59
  • @There: That indeed catches most cases. However, one case I can think of is if e.g. `T` is `int16_t` and `U` is `uint16_t`. But I bet with a bit more work, things like that can be solved. Of course, the easiest thing to do is simply to use @LindyDancer's original test. – Oliver Charlesworth Apr 16 '11 at 12:03
  • I just wonder what is the performance cost between doing the let's say lindy's method and fancy template checking. Because if lindy's is more efficient there is really little point of doing the whole sophisticated "templated" stuff. – There is nothing we can do Apr 16 '11 at 13:34
0

The safest way is to check it before doing the conversion. These templates do exactly that. Example:

/* unsigned -> signed, overflow */
safe_cast<short>(UINT_MAX);

/* unsigned -> unsigned, overflow */
safe_cast<unsigned char>(ULONG_MAX);

/* signed -> unsigned, overflow */
safe_cast<unsigned long>(-1);

/* signed -> signed, overflow */
safe_cast<signed char>(INT_MAX);

/* always works (no check done) */
safe_cast<long>(INT_MAX);

// giving these assertion failures results
(type)f <= (type)is_signed<To>::v_max
f <= (To)-1
f >= 0
f >= is_signed<To>::v_min && f <= is_signed<To>::v_max
Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • I've "improved" Oli's <> (see Edit 3) so I think it covers every case and it's "bit" less complicated than your solution (although excellent). I wonder what you think of my approach? – There is nothing we can do Apr 16 '11 at 14:24