簡體   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