2013-05-30 55 views
0

我有以下的馬可被定義一個問題:如何獲得C中的左移值?

TO_TI(a, b) ((b)<<13|(a)) 

然後我把下面的語句:

int c = TO_TI(1,2); 

然後我結果c傳遞給一個函數,這個函數,如何根據對值c和輸入一個計算值b

+0

c = 13; //不知道你在問什麼 – kenny

+1

不要用'int'!像這樣的宏只能使用'unsigned int'安全地(可逆地)工作。 – ams

回答

4

鑑於ac你不能(通常)計算b,因爲a和b是按位「或」在一起的,這是不可逆的(一般來說)。考慮a=101b=1,移位爲2.然後c=101b=0相同。沒有辦法知道。

如果您使用XOR而不是OR,或者您有更多信息,例如限制所涉及值的範圍,我們可能會取得更多進展。

+0

+1的評論:) – Ayse

+1

-1。這在迂腐的意義上是真實的,但是忽略了這一點。 – Potatoswatter

0

如果您確信一個沒有位中的一個,除了設置的前12位(當時|會破壞對B您的信息),可以使用&和右移扭轉操作:

b = (c & ~a) >> 13 

(該一〜是的按位取反)

編輯:確實甚至不是必需的,因爲通過右移的最低12個比特做&將被移出...

+0

如果在b上的左移操作中,它會導致b泄漏其MSB?假設原來的b有20位爲1,如果你在b上'<< 13',那麼你失去了這一點。 –

+1

那麼,那很討厭,但這就是生活;-) – urzeit

0

TO_TI遵循成語將多個值打包到位字段中。 (它也閃爍在你。)

b << 13乘 = 8192只要a是在13位長,即0 <= a < 8192,你可以通過模數與8192您恢復不需要b來恢復a ......反之亦然。

的整體思路是,ab應該很容易從TO_TI結果恢復,所以第一件事是看看周圍的宏定義源發現這是應該的逆過程宏。否則,c >> 13應該足以恢復b

應該注意的是,兩個數字都必須是正數,並且在要求的範圍內才能正常工作。如果TO_TI的作者從未提及過a不能大於8192,他們就睡着了。

0

如果我理解正確的問題,因爲Ç

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; 
1

將多個整數打包成一個較大的整數通常是一件有用的事情,編寫一個宏是一個很好的方法來讓它正確(儘管我更喜歡內聯函數)。

關鍵是你必須知道你在做什麼!如果您不能正確理解基本的位操作,或者至少遵循規則,那麼您將無法取回所投入的內容。

如果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位的系統。

規則:

  1. 明白你想要的位做什麼。
  2. 瞭解位運算符對簽名和無符號值所做的操作。
  3. 仔細測試邊界條件。

這就是爲什麼位字段被髮明,你應該強烈考慮使用它們。