简体   繁体   English

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

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

I have an app which is creating unique ids in the form of unsigned long int s. 我有一个应用程序,它以unsigned long int的形式创建唯一的id The app needs this precision. 该应用程序需要这种精度。

However, I have to send these ids in a protocol that only allows for int s. 但是,我必须在只允许int的协议中发送这些id 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 ? 所以我的问题是:如何将unsigned long int转换为int ,尤其是当unsigned long int大于int

edit: 编辑:

The protocol only supports int . 协议仅支持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. 发送消息的应用程序需要长时间知道唯一性,而接收者只需要在很短的时间内知道唯一性。

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. 例如,如果int是32位,则丢弃除UID的低位31位之外的所有位。 It will only yield non-negative values. 它只会产生非负值。

This loses information from the original uid , but you indicated that that's not a problem. 这会丢失原始uid ,但您表示这不是问题。

But your question is vague enough that it's hard to tell whether this will suit your purposes. 但是你的问题很模糊,很难说这是否符合你的目的。

As you know, one cannot in theory safely convert an unsigned long int to an int in the general case. 如你所知,一个人不能在理论上安全的转换unsigned long intint在一般情况下。 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. 使用<limits>标头的等效解决方案自然是可行的,但我不知道它比上面的更好。 (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. 关于性能,值得注意的是 - 除非你的编译器很老 - 除非使用,否则throw不会产生运行时负担。

@GManNickG adds the advice to inherit from std::exception . @GManNickG添加了从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. 您可以在此处阅读有关此类继承的更多信息。

Boost has numeric_cast : Boost有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. 如果转换会溢出,这将抛出异常,这可能是您想要的,也可能不是。

Keith Thompson's "& INT_MAX" is only necessary if you need to ensure that abbreviated_uid is non-negative. 只有在需要确保abbreviated_uid为非负数时,才需要Keith Thompson的“&INT_MAX”。 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). 如果这不是问题,并且你可以容忍负ID,那么一个简单的强制转换(C风格或static_cast())应该足够了, 如果 sizeof(unsigned long int)==sizeof(int) ,那么二进制表示在两端都是相同的(如果你将它转发回接收端的unsigned long int ,它将与发送端的值相同)。

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? 接收方是否将关于ID的响应发送回发送方,原始发送方(现在是响应的接收方)是否需要将其与原始的unsigned long int ID匹配? If so, you'll need some additional logic to match up the response with the original ID. 如果是这样,您将需要一些额外的逻辑来将响应与原始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. 该问题的一种可能解决方案是将ID分解为多个int部分,并将其重构为另一端的完全相同的unsigned long int值。 If you need help with that, I or someone else can help with that. 如果您需要帮助,我或其他人可以提供帮助。

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

You can try to use std::stringstream and atoi() : 您可以尝试使用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