如何安全地将`unsigned long int`转换为`int`?

时间:2012-07-08 22:53:13

标签: c++

我有一个应用程序,它以unsigned long int s的形式创建唯一的 ID 。该应用程序需要这种精度。

但是,我必须在仅允许int s的协议中发送这些 ID 。接收应用程序 - 协议 - 不需要这种精度。我的问题是:如何将unsigned long int转换为int,尤其是当unsigned long int大于int时?

编辑:

协议仅支持int。我很高兴知道如何避免“翻车问题”

发送消息的应用程序需要长时间知道唯一性,而接收者只需要在很短的时间内知道唯一性。

6 个答案:

答案 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)

只有当你需要确保abbreviated_uid是非负数时,才需要Keith Thompson的“&amp; INT_MAX”。如果这不是问题,并且您可以容忍否定ID,那么简单的强制转换(C风格或static_cast())就足够了,如果 {{ 1}},那么两端的二进制表示将是相同的(如果你将它转发回接收端的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::stringstreamatoi()

#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());