2015-11-27 41 views
0

以前,我有以下C代碼,通過該C代碼,我希望在演員製作後將變量'sample'的簽名擴展爲'signed short '變量'sample_unsigned'。向左旋轉和向右旋轉以用於標誌擴展(帶符號短)C

unsigned short sample_unsigned; 
signed short sample; 

sample = ((signed short) sample_unsigned << 4) >> 4; 

在二進制表示中,我期望'樣本'有最重要的位重複4次。舉例來說,如果:

sample_unsigned = 0x0800 (corresponding to "100000000000" in binary) 

我明白了「樣本」應該結果是:

sample = 0xF800 (corresponding to "1111100000000000" in binary) 

然而,「樣本」永遠結束是一樣的「sample_unsigned」,我不得不分割轉讓聲明如下,哪些工作。爲什麼這個?

sample = ((signed short) sample_unsigned << 4); 
sample >>= 4; 

回答

0

您的方法不起作用。沒有任何權利轉移會保留標誌。即使它只適用於16位int。對於> = 32位int,您必須手動將符號複製到高位,否則它只會來回移動相同的數據。一般來說,有符號值的位移很關鍵 - 有關詳細信息,請參見[標準](http://port70.net/~nsz/c/c11/n1570.html#6.5.7)。有些星座會調用未定義的行爲,最好避免使用它們,只使用無符號整數

對於大多數平臺,以下工作,但它不一定是更慢(在16位int平臺,它很可能甚至更快):

uint16_t usample; 
int16_t ssample; 

ssample = (int16_t)usample; 
if (ssample & 0x800) 
    ssample |= ~0xFFF; 

演員到int16_t是實現定義的;你的編譯器應說明它是如何進行的(幾乎。 ?)所有最近的實現都沒有執行額外的操作,只需在生成的代碼或編譯器文檔中進行驗證即可 - 或依賴intX_t使用2s補碼,這是標準保證的 - 與標準類型相反。

在32位平臺上,可能存在內部指令進行簽名擴展(例如ARM Cortex-M3/4 SBFX)。或者編譯器提供一個內置函數。根據您的使用情況和速度要求,可能適合使用它們。

更新:

另一種方法是使用一個位域結構:

struct { 
    int16_t val : 12; // assuming 12 bit signed value like above 
} extender; 

extender.val = usample; 
ssample = extender.val; 

這可能會導致使用我上面提出的同樣的彙編指令。

+0

我知道右移的符號擴展會產生未定義的行爲。我正在研究64位Ubuntu 12.04,在檢查了我的gcc文檔後,我決定嘗試一下。我需要做這種操作的原因是因爲我從一個提供10位有符號值的硬件平臺捕獲數據,後來我需要將其另存爲ASCII。正如你所建議的,我猜想使用'uint16_t'和'int16_t'應該是一個更穩定的解決方案。 –

+0

@CarlosCastro:我已經預料到了這種應用。我自己在嵌入式系統上使用它。只是不要依賴那個!上面的簡單條件將不會在具有條件移動指令的平臺上採用更多時鐘(IIRC,x64確實提供了這樣的功能,ARM明確做到這一點)。請注意,這是 - 像你問題中的代碼 - 是12位有符號整數,而不是10位;所以你必須調整口罩!如果只是爲了轉換,可能會有更簡單的技術。如果你可以節省內存空間,你甚至可以生成一個簡單的查找表。 – Olaf

+0

@CarlosCastro:我稍微更新了答案。如果答案有幫助,請隨時註冊。如果您需要最佳性能,只需對變體進行基準測試(但要小心**您實際測試的基準) – Olaf

0

這是因爲(signed short) sample_unsigned被自動轉換爲int如由於整數提升操作數。

sample = (signed short)((signed short) sample_unsigned << 4) >> 4; 

也可以工作。

+1

通過bitshift更改符號是未定義的行爲。並且'signed short'仍然會被強制爲'int'。 – Olaf

+1

而右移「簽名」並不能保證無論如何都保留了標誌(它甚至可以是UB)。 – Olaf

+0

內部(簽名的短)可能不需要,只需在執行正確的轉換之前進行簽名即可。如前所述,這是特定環境,但對大多數二進制補碼系統都有效。 – rcgldr