[英]Implementing bitwise operations in C
我正在嘗試在 C 中實現兩個按位函數:
set(unsigned *x, unsigned n, unsigned v)
--> 將值 x 的第 n 位設置為值 v。V 是 0 或 1,為了簡單起見,N 是 [0, 31]。
flip(unsigned *x, unsigned n)
--> 翻轉 x 中的第 N 位。 為簡單起見,假設 N 為 [0,31]。
我的實現:
void set(unsigned *x, unsigned n, unsigned v) {
*x = (1 << n) | v;
}
void flip(unsigned *x, unsigned n) {
*x = n ^ (1 << *x);
}
我的問題:這些功能不符合邏輯。
測試用例的輸出:
測試 set_bit()
SET_BIT(0x0000004e,2,0)返回0x00000004,但我們預計0x0000004a SET_BIT(0x0000006d,0,0)返回00000001,但我們預計0x0000006c SET_BIT(0x0000004e,2,1)返回0x00000005,但我們預計0x0000004e SET_BIT(0x0000006d,0,1)返回00000001但我們預計0x0000006d SET_BIT(0x0000004e,9,0)返回0x00000200,但我們預計0x0000004e SET_BIT(0x0000006d,4,0)返回0x00000010,但我們預計0x0000006d SET_BIT(0x0000004e,9,1)返回0x00000201,但我們預計0x0000024e SET_BIT( 0x0000006d,7,1) 返回 0x00000081 但我們期望 0x000000ed
測試 flip_bit()
flip_bit(0x0000004e,0)返回0x00004000,但我們預期0x0000004f flip_bit(0x0000004e,1)返回0x00004001,但我們預期0x0000004c flip_bit(0x0000004e,2)返回0x00004002,但我們預期0x0000004a flip_bit(0x0000004e,5)返回0x00004005,但我們預期 0x0000006e flip_bit(0x0000004e,9) 返回 0x00004009,但我們預期 0x0000024e
您應該為變量提供比必須用注釋解釋的 1 個字符更有意義的名稱。
在進行按位運算時,我們永遠不應該使用有符號數字,並且1
是有符號整數。 所以1<<31
是一個錯誤。
此外,您的函數集不能用於將位設置為值 0,因為按位 OR 不能那樣工作。 您要么需要單獨的函數來設置/清除,要么需要在函數內部包含一個分支if
語句,例如:
if(bit_value)
*value |= 1u<<n;
else
*value &= ~(1u<<n);
可用於任何類型的更合理的接口是使用字符數組。 然后你可以傳遞一個指向整數的指針,轉換它,它保證工作。
void bit_set (unsigned char* data, size_t byte, unsigned char bit)
{
data[byte] |= 1u << bit;
}
void bit_clear (unsigned char* data, size_t byte, unsigned char bit)
{
data[byte] &= ~(1u << bit);
}
void bit_toggle (unsigned char* data, size_t byte, unsigned char bit)
{
data[byte] ^= 1u << bit;
}
如果我們在邏輯上遵循您的代碼,我們可以看到發生了什么。 讓我們使用輸入 0x4e 和輸出 0x04 的第一個示例。 為簡單起見,我只看一個字節。
首先,您將 1 移位 N 次。 在這種情況下,N = 2。在二進制中,它看起來像這樣:
value : N
---------:--
00000001 : 0
00000010 : 1
00000100 : 2
接下來,我們用 V 來按位或該值,其中 V = 0:
00000100 | 00000000 => 00000100
最后,該值被分配給地址 X 處的值。在二進制中,值 00000100 相當於十六進制的 0x04,與您的實際輸出相匹配。
現在我們已經確定了邏輯錯誤,我們可以提出適當的說明,讓您到達您想要的位置。 我提出以下建議(盡管可能還有其他更好的方法)。
void set_bit(unsigned *x, unsigned n, unsigned v) {
unsigned temp = (1 << n);
*x = v ? *x | temp : *x & ~temp;
}
這里發生的事情是首先我們存儲由位移計算的值:00000100。然后我們選擇根據 V 的值執行兩條指令之一。
if v == 1
X : TEMP : HEX
01001110 | 00000100 => 01001110 : 0x4e
if v == 0
X : ~TEMP : HEX
01001110 & 11111011 => 01001010 : 0x4a
當 V = 0 時,這應該可以讓您獲得所需的輸出。
另一個函數實際上要簡單得多。 我們可以做一個按位異或:
void flip_bit(unsigned *x, unsigned n) {
unsigned temp = (1 << n);
*x ^= temp;
}
這是當 N = 0 時它在二進制中的樣子:
X : TEMP : HEX
01001110 ^ 00000001 => 01001111 : 0x4f
同樣,這符合您的預期輸出。
如果其中任何一個令人困惑,那么對按位運算符如何工作的簡單谷歌搜索應該可以提供見解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.