我有以下的馬可被定義一個問題:如何獲得C中的左移值?
TO_TI(a, b) ((b)<<13|(a))
然後我把下面的語句:
int c = TO_TI(1,2);
然後我結果c
傳遞給一個函數,這個函數,如何根據對值c和輸入一個計算值b
?
我有以下的馬可被定義一個問題:如何獲得C中的左移值?
TO_TI(a, b) ((b)<<13|(a))
然後我把下面的語句:
int c = TO_TI(1,2);
然後我結果c
傳遞給一個函數,這個函數,如何根據對值c和輸入一個計算值b
?
鑑於a
和c
你不能(通常)計算b
,因爲a和b是按位「或」在一起的,這是不可逆的(一般來說)。考慮a=101
和b=1
,移位爲2.然後c=101
與b=0
相同。沒有辦法知道。
如果您使用XOR而不是OR,或者您有更多信息,例如限制所涉及值的範圍,我們可能會取得更多進展。
+1的評論:) – Ayse
-1。這在迂腐的意義上是真實的,但是忽略了這一點。 – Potatoswatter
如果您確信一個沒有位中的一個,除了設置的前12位(當時|會破壞對B您的信息),可以使用&和右移扭轉操作:
b = (c & ~a) >> 13
(該一〜是的按位取反)
編輯:確實甚至不是必需的,因爲通過右移的最低12個比特做&將被移出...
如果在b上的左移操作中,它會導致b泄漏其MSB?假設原來的b有20位爲1,如果你在b上'<< 13',那麼你失去了這一點。 –
那麼,那很討厭,但這就是生活;-) – urzeit
宏TO_TI
遵循成語將多個值打包到位字段中。 (它也閃爍在你。)
b << 13
乘 = 8192只要a
是在13位長,即0 <= a < 8192
,你可以通過模數與8192您恢復不需要b
來恢復a
......反之亦然。
的整體思路是,a
和b
應該很容易從TO_TI
結果恢復,所以第一件事是看看周圍的宏定義源發現這是應該的逆過程宏。否則,c >> 13
應該足以恢復b
。
應該注意的是,兩個數字都必須是正數,並且在要求的範圍內才能正常工作。如果TO_TI
的作者從未提及過a
不能大於8192,他們就睡着了。
如果我理解正確的問題,因爲Ç從
c = b<<13 | a;
導致我們可以發現原來一個和b?
這取決於
長度的一個(比特數):上述除的問題,如果一個 MSB(最高顯著位)爲2^13個或更多時,|
操作會影響其中b是移位(b << 13
)之後,並且因此可以不知道,如果從位13的ç值是從原來的b,或從一個
的b長度:移位13位是由2^13(8192)乘以b,並且如果b足夠原來大,移位後它可能會溢出Ç,即結果將不符合大小(長度),並且從以下方法中檢索的結果將小於原始的b。
所以,如果一個小於8192(2^13),但陽性(否則其MSB將達到b移位)和b左移13位不溢出ç可以檢索一個和b,使用
a = c & 8191; // 2^13 - 1 or 0x1fff in hexa
b = c >> 13;
將多個整數打包成一個較大的整數通常是一件有用的事情,編寫一個宏是一個很好的方法來讓它正確(儘管我更喜歡內聯函數)。
關鍵是你必須知道你在做什麼!如果您不能正確理解基本的位操作,或者至少遵循規則,那麼您將無法取回所投入的內容。
如果a
是一個正整數,則您的TO_TI宏將正常工作不超過12位。 b
不得超過20位數據(假設爲32位字)。
如果a
是無符號就可以提取這樣的:
unsigned int a = c & 0xFFF;
但是,如果a
簽訂,那麼你必須「符號擴展」的價值,像這樣:
int a = ((int)c << 20) >> 20;
同樣,如果b
已簽名,則必須進行符號擴展,但這很容易:
int b = (int)c >> 12;
但是,是b
是無符號的,你必須非常小心不簽署,擴展它:最後,
unsigned int b = (unsigned int)c >> 12;
,如果你想允許a
有負值,那麼宏必須這樣定義:
#define TO_TI(a, b) ((b)<<13|((a)&0xFFF))
(否則的a
符號位將覆蓋b
)
如果有三個或三個以上值編碼成相同的整數,然後事情變得更加毛茸茸。並且要注意int
有64位的系統。
規則:
這就是爲什麼位字段被髮明,你應該強烈考慮使用它們。
c = 13; //不知道你在問什麼 – kenny
不要用'int'!像這樣的宏只能使用'unsigned int'安全地(可逆地)工作。 – ams