繁体   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