繁体   English   中英

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

[英]How can I safely convert `unsigned long int` to `int`?

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

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

编辑:

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

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

这是一种可能的方法:

#include <climits>
unsigned long int uid = ...;
int abbreviated_uid = uid & INT_MAX;

例如,如果int是32位,则丢弃除UID的低位31位之外的所有位。 它只会产生非负值。

这会丢失原始uid ,但您表示这不是问题。

但是你的问题很模糊,很难说这是否符合你的目的。

如你所知,一个人不能在理论上安全的转换unsigned long intint在一般情况下。 然而,在许多感兴趣的实际情况中,人们确实可以这样做,其中整数不是太大。

我可能会定义并使用它:

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继承的建议。 我个人对此没有强烈的感觉,但建议是有充分理由和赞赏的,我认为没有理由不遵循它。 您可以在此处阅读有关此类继承的更多信息。

Boost有numeric_cast

unsigned long l = ...;
int i = boost::numeric_cast<int>(l);

如果转换会溢出,这将抛出异常,这可能是您想要的,也可能不是。

只有在需要确保abbreviated_uid为非负数时,才需要Keith Thompson的“&INT_MAX”。 如果这不是问题,并且你可以容忍负ID,那么一个简单的强制转换(C风格或static_cast())应该足够了, 如果 sizeof(unsigned long int)==sizeof(int) ,那么二进制表示在两端都是相同的(如果你将它转发回接收端的unsigned long int ,它将与发送端的值相同)。

接收方是否将关于ID的响应发送回发送方,原始发送方(现在是响应的接收方)是否需要将其与原始的unsigned long int ID匹配? 如果是这样,您将需要一些额外的逻辑来将响应与原始ID相匹配。 如果是这样,发布一个表明此类要求的编辑,我(或其他人)可以提出解决该问题的方法。 该问题的一种可能解决方案是将ID分解为多个int部分,并将其重构为另一端的完全相同的unsigned long int值。 如果您需要帮助,我或其他人可以提供帮助。

我来到这里,因为我必须有一个解决方案,将更大的整数类型转换为更小的类型,即使可能丢失信息。

我想出了一个使用模板的非常简洁的解决方案:

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;
}

您可以尝试使用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());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM