74

My question is that

I have a size_t data, but now I want to convert it to double or int.

If I do something like

 size_t data = 99999999;
 int convertdata = data;

the compiler will report warning. because it maybe overflow.

Do you have some method like the boost or some other method to do the convert?

chema989
  • 3,962
  • 2
  • 20
  • 33
user2701639
  • 861
  • 2
  • 8
  • 13

5 Answers5

99

A cast, as Blaz Bratanic suggested:

size_t data = 99999999;
int convertdata = static_cast<int>(data);

is likely to silence the warning (though in principle a compiler can warn about anything it likes, even if there's a cast).

But it doesn't solve the problem that the warning was telling you about, namely that a conversion from size_t to int really could overflow.

If at all possible, design your program so you don't need to convert a size_t value to int. Just store it in a size_t variable (as you've already done) and use that.

Converting to double will not cause an overflow, but it could result in a loss of precision for a very large size_t value. Again, it doesn't make a lot of sense to convert a size_t to a double; you're still better off keeping the value in a size_t variable.

(R Sahu's answer has some suggestions if you can't avoid the cast, such as throwing an exception on overflow.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • I recently ran into a trouble where a function that returned double was meant to return npos when it failed, but when i checked (==) the result of the function against npos it didn't return true when it should. Checking on the console i discovered that the double casted npos was 1 integer higher than the non casted npos (size_t) – Coyoteazul Jun 13 '19 at 01:31
  • @Coyoteazul: That's a poorly designed function. Even worse, it's likely to "work" on a 32-bit system. – Keith Thompson Jun 13 '19 at 03:12
  • yup. I actually thought double had a bigger capacity than size_t, so i didn't think that casting npos would be a trouble. I commented it in case someone runs into the ame trouble – Coyoteazul Jun 14 '19 at 01:17
  • @Coyoteazul: On many modern system, `double` and `size_t` are both 64 bits. For `size_t` they're all value bits. `double` devotes a bit to the sign and several more to the exponent. `double` can easily hold a number with the magnitude of `npos` (`SIZE_MAX`), but it can't store its full precision. – Keith Thompson Jun 14 '19 at 02:36
25

If your code is prepared to deal with overflow errors, you can throw an exception if data is too large.

size_t data = 99999999;
if ( data > INT_MAX )
{
   throw std::overflow_error("data is larger than INT_MAX");
}
int convertData = static_cast<int>(data);
Løiten
  • 3,185
  • 4
  • 24
  • 36
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    Useful reply. I filed an edit to add this content into the end of the accepted answer so that future readers see a complete response in one place. – srm Apr 09 '18 at 18:23
20

Static cast:

static_cast<int>(data);
Blaz Bratanic
  • 2,279
  • 12
  • 17
  • 1
    is it possible to cause the overflow, because the range of size_t is large than the range of int. – user2701639 Mar 04 '14 at 22:26
  • 1
    @user2701639 Well, what do you want to happen in that scenario? – David Heffernan Mar 04 '14 at 22:27
  • @user2701639 _is it possible to cause the overflow ..._ Not with `double`. – πάντα ῥεῖ Mar 04 '14 at 22:28
  • 2
    As written, yes, this will cause an overflow if `data` is larger than the value that fits in `int` - and as such, could cause "interesting" issue, such as a negative value in `convertdata`, and when something you consider a size is negative, you know something is horribly wrong. Also, selected values of `data` may cause the value in `convertdata` to be zero, other values may represent the size as a very small positive number, although the original size is huge. – Mats Petersson Mar 04 '14 at 22:41
13

You can use Boost numeric_cast.

This throws an exception if the source value is out of range of the destination type, but it doesn't detect loss of precision when converting to double.

Whatever function you use, though, you should decide what you want to happen in the case where the value in the size_t is greater than INT_MAX. If you want to detect it use numeric_cast or write your own code to check. If you somehow know that it cannot possibly happen then you could use static_cast to suppress the warning without the cost of a runtime check, but in most cases the cost doesn't matter anyway.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    that exactly what needs if you can't avoid such cast, but want program to let you know if out_of_range happens. – Arkady Nov 04 '15 at 12:35
4

Assuming that the program cannot be redesigned to avoid the cast (ref. Keith Thomson's answer):

To cast from size_t to int you need to ensure that the size_t does not exceed the maximum value of the int. This can be done using std::numeric_limits:

int SizeTToInt(size_t data)
{
    if (data > std::numeric_limits<int>::max())
        throw std::exception("Invalid cast.");
    return std::static_cast<int>(data);
}

If you need to cast from size_t to double, and you need to ensure that you don't lose precision, I think you can use a narrow cast (ref. Stroustrup: The C++ Programming Language, Fourth Edition):

template<class Target, class Source>
Target NarrowCast(Source v)
{
    auto r = static_cast<Target>(v);
    if (static_cast<Source>(r) != v)
        throw RuntimeError("Narrow cast failed.");
    return r;
}

I tested using the narrow cast for size_t-to-double conversions by inspecting the limits of the maximum integers floating-point-representable integers (code uses googletest):

EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 2 })), size_t{ IntegerRepresentableBoundary() - 2 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 1 })), size_t{ IntegerRepresentableBoundary() - 1 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() })), size_t{ IntegerRepresentableBoundary() });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 1 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 2 })), size_t{ IntegerRepresentableBoundary() + 2 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 3 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 4 })), size_t{ IntegerRepresentableBoundary() + 4 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 5 }), std::exception);

where

constexpr size_t IntegerRepresentableBoundary()
{
    static_assert(std::numeric_limits<double>::radix == 2, "Method only valid for binary floating point format.");
    return size_t{2} << (std::numeric_limits<double>::digits - 1);
}

That is, if N is the number of digits in the mantissa, for doubles smaller than or equal to 2^N, integers can be exactly represented. For doubles between 2^N and 2^(N+1), every other integer can be exactly represented. For doubles between 2^(N+1) and 2^(N+2) every fourth integer can be exactly represented, and so on.

Community
  • 1
  • 1
Ida
  • 3,417
  • 1
  • 11
  • 11