我有一個 16 位字(短)。我想取低 13 位并將它們保存在一個新的短位元組中,同時保留符號(即如果第 12 位是 1,那么我希望新字中的第 13-15 位也為 1,但如果第 12 位是a 0,那么我希望新單詞中的第 13-15 位為 0)。
例如,如果我有
short a = 0xDADD // 0b1101101011011101
short b = 0xFADD // 0b1111101011001110
要么
short a = 0xABCD // 0b1010101111001101
short b = 0x0BCD // 0b0000101111001101
我可以用條件來做到這一點,但如果可以的話,我想盡量避免這種情況,并堅持盡可能少的按位運算。另一種選擇是向左移動 3 位,然后是 3 位算術右移,但據我了解,大多數 C 編譯器將>>運算子解釋為邏輯移位。有沒有辦法強制算術移位?
提前致謝
uj5u.com熱心網友回復:
您可以使用(x & 0x1fff ^ 0x1000) - 0x1000. 在屏蔽低 13 位之后,這會翻轉第 12 位并減去 4096 (2 12 )。
要查看此方法,請考慮位 12 的值b(0 或 1)和位 11 到 0 的值c(0 到 4095)。在 13 位二進制補碼表示中,位 12 表示 -4096,因此表示的值為?4096? b c。相反,在我們更廣泛的整數型別中,我們有 4096? b c。翻轉b得到 4096?(1- b ) c,然后減去 4096 得到 4096?(? b ) c = ?4096? b c,這是所需的結果。
uj5u.com熱心網友回復:
這歸結為“從恒定位寬擴展的符號”,Bit Twiddling Hacks 為此提供了優化的解決方案:
本質上,您只需struct使用包含預期位數的欄位宣告自己 a,并通過此類結構上的欄位引導您的分配。對于您的情況,您只需將其調整為 13 位的情況:
short a = ...;
short b;
struct {signed short x:13;} s;
b = s.x = a;
這樣做的好處是您不必自己嘗試任何實際的位旋轉(這可能會在架構 X 上產生最佳代碼,但在架構 Y 上會產生糟糕的結果),您只需讓編譯器為您確定目標的最佳解決方案。
例子:
int main(void)
{
short a;
short b;
struct {signed short x:13;} s;
a = 0xDADD;
b = s.x = a;
printf("hx\nhx\n\n", a, b);
a = 0xABCD;
b = s.x = a;
printf("hx\nhx\n", a, b);
}
在線嘗試!
輸出:
dadd
fadd
abcd
0bcd
如果您實際上是在 C 上使用 C ,則使用模板函式可以更輕松地使用模板函式(無需為每種情況手動重寫,或使用 hacky 不可靠的基于宏的代碼):
template <typename T, unsigned B>
inline T signextend(const T x)
{
struct {T x:B;} s;
return s.x = x;
}
這將用例簡化為:
short b = signextend<signed short, 13>(a);
Obviously, if you must use C for whatever reason, this is not an option, but template hacks like this are sometimes worth a switch even if you largely stick to C idioms.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/448236.html
