我有一个应用程序,它以unsigned long int
s的形式创建唯一的 ID 。该应用程序需要这种精度。
但是,我必须在仅允许int
s的协议中发送这些 ID 。接收应用程序 - 协议 - 不需要这种精度。我的问题是:如何将unsigned long int
转换为int
,尤其是当unsigned long int
大于int
时?
协议仅支持int
。我很高兴知道如何避免“翻车问题”
发送消息的应用程序需要长时间知道唯一性,而接收者只需要在很短的时间内知道唯一性。
答案 0 :(得分:9)
这是一种可行的方法:
#include <climits>
unsigned long int uid = ...;
int abbreviated_uid = uid & INT_MAX;
例如,如果int
是32位,则丢弃除UID的低位31位以外的所有位。它只会产生非负值。
这会丢失原始uid
的信息,但您表示这不是问题。
但是你的问题很模糊,很难说这是否符合你的目的。
答案 1 :(得分:3)
如您所知,在一般情况下,理论上无法将unsigned long int
安全地转换为int
。然而,在许多感兴趣的实际情况中,人们确实可以这样做,其中整数不是太大。
我可能会定义并使用它:
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;
}
使用<limits>
标题的等效解决方案自然是可行的,但我不知道它比上面的更好。 (如果代码处于时间关键循环并且可移植性不是一个因素,那么您可以在汇编中对其进行编码,直接测试一些或多个感兴趣的位,但除了作为汇编语言的练习外,这将是一个麻烦。)
关于性能,值得注意的是 - 除非您的编译器非常旧 - throw
除非使用,否则不会产生运行时负担。
@GManNickG添加了从std::exception
继承的建议。我个人对此没有强烈的感觉,但建议是有充分理由和赞赏的,我认为没有理由不遵循它。 You can read more about such inheritance here.
答案 2 :(得分:3)
Boost有numeric_cast
:
unsigned long l = ...;
int i = boost::numeric_cast<int>(l);
如果转换会溢出,这将抛出异常,这可能是您想要的,也可能不是。
答案 3 :(得分:3)
sizeof(unsigned long int)==sizeof(int)
,它将与发送端的值相同)。
接收方是否会向发送方发送有关ID的响应,原始发件人(现在是响应的接收方)是否需要将其与原始unsigned long int
ID相匹配?如果是这样,您将需要一些额外的逻辑来将响应与原始ID相匹配。如果是这样,发布一个表明此类要求的编辑,我(或其他人)可以提出解决该问题的方法。该问题的一种可能解决方案是将ID分解为多个unsigned long int
个片段,并将其重构为另一端的完全相同的int
值。如果您需要帮助,我或其他人可以提供帮助。
答案 4 :(得分:1)
我之所以这样,是因为我必须有一个解决方案,可以将更大的整数类型转换为更小的类型,即使可能会丢失信息。
我想出了一个使用模板的非常简洁的解决方案:
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;
}
答案 5 :(得分:-1)
您可以尝试使用std::stringstream
和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());