2009-08-18 32 views
7

我有兩個16位短褲(s1和s2),我試圖將它們組合成一個32位整數(i1)。根據我正在處理的規範,s1是最重要的單詞,而s2是最不重要的單詞,並且組合的單詞似乎被簽名。 (即,s1的最高位是符號)。最簡單的方法來將兩個短褲合併爲一個int

將s1和s2組合起來最簡潔的方法是什麼?

我估計像

const utils::int32 i1 = ((s1<<16) | (s2)); 

會做,它似乎工作,但我很擔心左移短按16

此外,我感興趣的是使用工會來完成工作的想法,關於這是好還是壞的想法的任何想法?

回答

1

嘗試data.second explicite投射到short類型,如:

const utils::int32 combineddata = ((data.first<<16) | ((short)data.second)); 

編輯:我是C#開發,很可能在你的代碼語言鑄造看起來不同,但想法可能是相同的。

0

您希望在執行shift之前將data.first強制轉換爲int32,否則當它被分配給組合數據時,它會在存儲器被自動提升之前溢出存儲器。

嘗試:

const utils::int32 combineddata = (static_cast<utils::int32>(data.first) << 16) | data.second; 

當然這是假設data.first和data.second是保證是精確的16位長的類型,否則,你有更大的問題。

我真的不明白你的陳述「如果data.second變得太大,|他將不會考慮到他們都是短褲的事實。」

編輯:尼爾絕對正確的簽名。

+5

在短褲的情況下,我不確定這是否有必要。該標準具有:「操作數應是整數或枚舉類型,並執行整體升級,結果的類型是升級的左操作數的類型」。因此,空格將被隱式提升爲int。 – 2009-08-18 15:42:29

+0

呵呵。我不知道 - 我想這是因爲我總是對數據類型大小超級偏執狂。感謝指針。 – 2009-08-18 15:59:43

+0

因爲在16位整數的平臺上肯定會需要演員陣容,所以這很好是偏執狂! – 2009-08-18 17:20:29

13

你在做什麼只有在短褲和int都是無符號時纔有意義。如果任何一條短褲都被簽名並且具有負值,那麼將它們組合成一個整數的想法是沒有意義的,除非您已經提供了一個特定於域的規範來涵蓋這種可能性。

+0

我同意發佈的代碼有一個符號擴展錯誤,並且將兩個in16_tss「合併」到一個int32_t的請求很奇怪。但我不認爲這是無意義的,因爲可以爲操作定義一些語義。 – 2009-08-18 16:10:30

+1

你讀過我答案的最後15個單詞嗎? – 2009-08-18 16:14:19

+0

是的,它看起來像硬件接口將一個有符號整數分成2,然後發送它,因爲它有一個MSW和一個LSW,但它顯然是2補碼簽名。所以我需要從中明智地重組數據。 – deworde 2009-08-18 17:20:38

6

你有什麼看起來幾乎是正確的,但如果第二部分是否定的,可能會失敗;隱式轉換爲int可能會簽名擴展並用1填充高16位。對無符號短片進行轉換可能會阻止這種情況的發生,但最好的辦法是屏蔽掉這些位。

const utils::int32 combineddata = ((data.first<<16) | ((data.second) & 0xffff)); 
+0

非常好,這很有意義。 – deworde 2009-08-18 17:18:48

+0

事實上,隱式轉換爲int會導致問題。例如,如果data.first爲負數,'data.first << 16'也將在此發佈的代碼中調用未定義的行爲。因此這不是一個好的解決方案。總體而言,將移位運算符與有符號數一起使用並不是一個好主意。更好的解決方案:'uint32_t u32 =(uint32_t)data.first << 16 | (uint32_t的)data.second; combineddate =(int32_t)u32;' – Lundin 2017-05-12 09:40:59

-1

使用union來完成這項工作看起來是一個不錯的選擇,但由於處理器的endian差異,這是一個可移植性問題。這是可行的,但你需要準備好基於目標體系結構來修改你的聯盟。位移是便攜式的,但請寫一個函數/方法來爲你做。內聯,如果你喜歡。

至於短褲的簽名,對於這種類型的操作,它的意義不是數據類型。換句話說,如果s1和s2意味着被解釋爲32位字的兩半,如果你做了一些會導致s2被符號擴展的事情,那麼第15位的設置就很重要。請參閱Mark Ransoms的回答,這可能會更好,因爲

inline utils::int32 CombineWord16toLong32(utils::int16 s1, utils::int16 s2) 
{ 
    return ((s1 <<16) | (s2 & 0xffff)); 
} 
3

因爲沒有人發佈它,所以這是工會的樣子。但是,關於endian-ness的評論肯定適用。

大端:

typedef union { 
    struct { 
     uint16_t high; 
     uint16_t low; 
    } pieces; 
    uint32_t all; 
} splitint_t; 

小端:

typedef union { 
    struct { 
     uint16_t low; 
     uint16_t high; 
    } pieces; 
    uint32_t all; 
} splitint_t; 
+0

請注意,該規範對此提供了零保證。它特別在C中被廣泛使用,我懷疑任何編譯器都會故意破壞它,但嚴格地說它是未定義的行爲。通常不能寫入結構的一個成員並從另一個結構讀取。 – jalf 2009-08-18 17:25:31

+0

請注意,標準並不保證'all'在分配給'high'和'low'之後將有任何明智的數據,反之亦然。該解決方案不具有便攜性。 – Juliano 2009-08-18 17:25:58

+0

沒有理由爲此使用聯合,你實現的只是可移植性問題。並且類型剔除在C++中不是很好定義,不像C. – Lundin 2017-05-12 09:42:37

3

我知道這是一個老的文章,但本質量貼出答案是鬱悶......

這些是要考慮的問題:

  • 短整數(或其他小整數類型)的隱式整數提升將導致經過簽名的int類型的操作數。無論小整數類型的符號如何,都會發生這種情況。整數提升發生在移位操作和按位或運算中。
  • 在移位運算符的情況下,結果類型是升級左操作數的類型。在按位OR的情況下,所得到的類型是從「通常的算術轉換」中獲得的。
  • 左移負數會導致未定義的行爲。右移負數會導致實現定義的行爲(邏輯與算術移位)。因此,在所有使用案例中,有符號數字不應與99%的位移​​一起使用。
  • 工會,陣列和類似的解決方案很糟糕,因爲他們使代碼依賴性依賴。另外,在C++中鍵入雙擊也不是明確定義的行爲(與C不同)。基於指針的解決方案是不好的,因爲它們最終會違反「嚴格的別名規則」。因此

一個適當的解決方案:

  • 使用操作數與保證是無符號,並不會被隱式類型提升。
  • 使用位移,因爲這些位移是獨立性的。

它看起來是這樣的:

int32_t i32 = (int32_t)((uint32_t)s1<<16 | (uint32_t)s2); 

任何其他的解決方案是非常值得懷疑的,在最好的非便攜。

+0

Heh。說實話,回過頭看8年的經驗,唯一真正能夠回答這個問題的人是硬件API的設計者本人。我當時想知道他們是否使用了已知的標準合併方法,但是...... – deworde 2017-05-12 10:06:29

+0

@deworde你是什麼意思「硬件API」?這個代碼與金屬接近。 – Lundin 2017-05-12 10:59:14

相關問題