簡體   English   中英

向左和向右旋轉以使用C轉換(帶符號短號)進行符號擴展

[英]Rotate left and back to the right for sign extension with (signed short) cast in C

以前,我有以下C代碼,通過該代碼,我打算在將變量“ sample_unsigned”的“ signed short”轉換為變量后,對變量“ sample”進行符號擴展。

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'總是以與'sample_unsigned'相同的方式結束,因此我不得不按如下方式拆分賦值語句,這是可行的。 為什么這個?

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

這是因為由於整數提升, (signed short) sample_unsigned整數(signed short) sample_unsigned會自動轉換為int作為操作數。

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

也會工作。

您的方法無效。 沒有保證的右移將保留該標志。 即使,它也只適用於16位int 對於> = 32位int您必須手動將符號復制到高位,否則它將來回移動相同的數據。 通常,有符號值的位偏移至關重要-有關詳細信息,請參見[standard]( 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_tint16_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;

這可能導致使用我上面建議的相同的匯編程序指令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM