簡體   English   中英

在 C 中實現按位運算

[英]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.

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