Reputation: 14415
I have an app which is creating unique ids in the form of unsigned long int
s. The app needs this precision.
However, I have to send these ids in a protocol that only allows for int
s. The receiving application – of the protocol – does not need this precision. So my questions is: how can I convert an unsigned long int
to an int
, especially when the unsigned long int
is larger than an int
?
The protocol only supports int
. I would be good to know how to avoid "roll-over problems"
The application sending the message needs to know the uniqueness for a long period of time, whereas the receiver needs to know the uniqueness only over a short period of time.
Upvotes: 10
Views: 64599
Reputation: 89
You can try to use std::stringstream
and atoi()
:
#include <sstream>
#include <stdlib.h>
unsigned long int a = ...;
std::stringstream ss;
ss << a;
std::string str = ss.str();
int i = atoi(str.c_str());
Upvotes: 0
Reputation: 16825
I came along this, since I had to have a solution for converting larger integer types to smaller types, even when potentially loosing information.
I came up with a pretty neat solution using templates:
template<typename Tout, typename Tin>
Tout toInt(Tin in)
{
Tout retVal = 0;
if (in > 0)
retVal = static_cast<Tout>(in & std::numeric_limits<Tout>::max());
else if (in < 0)
retVal = static_cast<Tout>(in | std::numeric_limits<Tout>::min());
return retVal;
}
Upvotes: 1
Reputation: 14434
As you know, one cannot in theory safely convert an unsigned long int
to an int
in the general case. However, one can indeed do so in many practical cases of interest, in which the integer is not too large.
I would probably define and use this:
struct Exc_out_of_range {};
int make_int(const unsigned long int a) {
const int n = static_cast<int>(a);
const unsigned long int a2 = static_cast<unsigned long int>(n);
if (a2 != a) throw Exc_out_of_range();
return n;
}
An equivalent solution using the <limits>
header naturally is possible, but I don't know that it is any better than the above. (If the code is in a time-critical loop and portability is not a factor, then you could code it in assembly, testing the bit or bits of interest directly, but except as an exercise in assembly language this would be a bother.)
Regarding performance, it is worth noting that -- unless your compiler is very old -- the throw
imposes no runtime burden unless used.
@GManNickG adds the advice to inherit from std::exception
. I personally don't have a strong feeling about this, but the advice is well founded and appreciated, and I see little reason not to follow it. You can read more about such inheritance here.
Upvotes: 3
Reputation: 7873
Keith Thompson's "& INT_MAX" is only necessary if you need to ensure that abbreviated_uid is non-negative. If that's not an issue, and you can tolerate negative IDs, then a simple cast (C-style or static_cast()) should suffice, with the benefit that if sizeof(unsigned long int)==sizeof(int)
, then the binary representation will be the same on both ends (and if you cast it back to unsigned long int
on the receiving end it will be the same value as on the sending end).
Does the receiver send responses back to the sender regarding the IDs, and does the original sender (now the receiver of the response) need to match this up with the original unsigned long int
ID? If so, you'll need some additional logic to match up the response with the original ID. If so, post an edit indicating such requirement and I (or others) can suggest ways of addressing that issue. One possible solution to that issue would be to break up the ID into multiple int
pieces and reconstruct it into the exact same unsigned long int
value on the other end. If you need help with that, I or someone else can help with that.
Upvotes: 3
Reputation: 49802
Boost has numeric_cast
:
unsigned long l = ...;
int i = boost::numeric_cast<int>(l);
This will throw an exception if the conversion would overflow, which may or may not be what you want.
Upvotes: 4
Reputation: 263177
Here's one possible approach:
#include <climits>
unsigned long int uid = ...;
int abbreviated_uid = uid & INT_MAX;
If int
is 32 bits, for example, this discards all but the low-order 31 bits of the UID. It will only yield non-negative values.
This loses information from the original uid
, but you indicated that that's not a problem.
But your question is vague enough that it's hard to tell whether this will suit your purposes.
Upvotes: 16