Converting Integer Types

Viewed 122

How does one convert from one integer type to another safely and with setting off alarm bells in compilers and static analysis tools?

Different compilers will warn for something like:

int i = get_int();
size_t s = i;

for loss of signedness or

size_t s = get_size();
int i = s;

for narrowing.

casting can remove the warnings but don't solve the safety issue.

Is there a proper way of doing this?

4 Answers

You can try boost::numeric_cast<>.

boost numeric_cast returns the result of converting a value of type Source to a value of type Target. If out-of-range is detected, an exception is thrown (see bad_numeric_cast, negative_overflow and positive_overflow ).

How does one convert from one integer type to another safely and with setting off alarm bells in compilers and static analysis tools?

Control when conversion is needed. As able, only convert when there is no value change. Sometimes, then one must step back and code at a higher level. IOWs, was a lossy conversion needed or can code be re-worked to avoid conversion loss?

It is not hard to add an if(). The test just needs to be carefully formed.

Example where size_t n and int len need a compare. Note that positive values of int may exceed that of size_t - or visa-versa or the same. Note in this case, the conversion of int to unsigned only happens with non-negative values - thus no value change.

int len = snprintf(buf, n, ...);
if (len < 0 || (unsigned)len >= n) {
  // Handle_error();
}

unsigned to int example when it is known that the unsigned value at this point of code is less than or equal to INT_MAX.

unsigned n = ...
int i = n & INT_MAX;

Good analysis tools see that n & INT_MAX always converts into int without loss.

There is no built-in safe narrowing conversion between int types in c++ and STL. You could implement it yourself using as an example Microsoft GSL.

Theoretically, if you want perfect safety, you shouldn't be mixing types like this at all. (And you definitely shouldn't be using explicit casts to silence warnings, as you know.) If you've got values of type size_t, it's best to always carry them around in variables of type size_t.

There is one case where I do sometimes decide I can accept less than 100.000% perfect type safety, and that is when I assign sizeof's return value, which is a size_t, to an int. For any machine I am ever going to use, the only time this conversion might lose information is when sizeof returns a value greater than 2147483647. But I am content to assume that no single object in any of my programs will ever be that big. (In particular, I will unhesitatingly write things like printf("sizeof(int) = %d\n", (int)sizeof(int)), explicit cast and all. There is no possible way that the size of a type like int will not fit in an int!)

[Footnote: Yes, it's true, on a 16-bit machine the assumption is the rather less satisfying threshold that sizeof won't return a value greater than 32767. It's more likely that a single object might have a size like that, but probably not in a program that's running on a 16-bitter.]

Related