C语言位运算总结

常见位运算:

取反~,按位与&,按位或|,按位异或^,逻辑左移<<, 逻辑右移>>,算术左移<<, 算术右移>> 

1、用掩码将最低n位置为0

下面这个例子,是将某输入数字的最低11位强制置为0,其他位保持不变。

void BitTest1()
{
    uint32_t x = 0xF596DF32;
    uint32_t mask = 0xFFFFF800;
    x = x & mask;
}

该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:

①使用取反将0置为全1:~0

②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n

使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)

uint32_t mask = (~0) << 11;

2、用掩码保留最低n位,其他位置为0

下面这个例子,是将某输入数字的最低10位的值保留,其他位全部置为0。

void BitTest2()
{
    uint32_t x = 0xF596DF32;
    uint32_t mask = 0x3FF;
    x = x & mask;
}

该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:

①使用取反将0置为全1:~0

②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n

③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)

使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)

uint32_t mask = ~((~0) << 10);

3、用掩码取出第m位开始的连续n位的值

下面这个例子,是将某输入数字的bit4~bit14的值保留,其他位全部置为0。(注意此例中最低位为bit0,最高位为bit31)

void BitTest3()
{
    uint32_t x = 0xF596DF32;
    uint32_t mask = 0x7FF0;
    x = x & mask;
}

该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:

①使用取反将0置为全1:~0

②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n

③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)

④再次左移m位,形成中间需要的n位为1,其他位为0的掩码:(~((~0) << n)) << m

使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)

uint32_t mask = (~((~0) << 11)) << 4;

如果希望进一步获得bit4~bit14中所存放的数值大小,可在完成以上操作以后,再将结果右移4位:

uint32_t value = x >> 4;

在这一步中需要小心前面得到的结果不能是负数。

由于取出某几个连续位中的值的功能在编码中比较常用,可以将该功能写成一个函数/宏供调用:

uint32_t GetBits(uint32_t number, size_t start, size_t count)
{
    return (number & ((~((~0) << count)) << start)) >> start;
}

4、用掩码将第m位开始的连续n位的值置0

下面这个例子,是将某输入数字的bit4~bit14的值置为0,其他位保持不变。(注意此例中最低位为bit0,最高位为bit31)

void BitTest4()
{
    uint32_t x = 0xF596DF32;
    uint32_t mask = 0xFFFF800F;
    x = x & mask;
}

该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:

①使用取反将0置为全1:~0

②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n

③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)

④再次左移m位,形成中间需要置0的n位为1,其他位为0的掩码:(~((~0) << n)) << m

⑤再次取反,形成中间需要置0的n位为0,其他位为1的掩码:~((~((~0) << n)) << m)

使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)

uint32_t mask = ~((~((~0) << 11)) << 4);

5、用掩码将部分连续的位置为1

如果需要将某些位置为1而不是0,方法与前面类似,只不过需要指定位为1的掩码,操作是按位或而不是按位与。

例如:将某输入数字的bit4~bit14的值置为1,其他位保持不变。(注意此例中最低位为bit0,最高位为bit31)

void BitTest5()
{
    uint32_t x = 0xF596DF32;
    uint32_t mask = (~((~0) << 11)) << 4;
    x = x | mask;
}

6、将第m位开始的连续n位的值设置成指定的值

如果要将某个值填入到指定的位置中,可以采用类似3.2.5的方法,但是此时的“掩码”不再是全1,而是需要设置的值。

void BitTest6()
{
    uint32_t x = 0xF596DF02;
    uint32_t value = 5 << 4;  // 将5设置到bit4~bit7中
    x = x | value;  // 结果为0xF596DF52
}

需要注意的是,在用这种方法填值以前,一定要保证目标位置已经是全0,否则结果不正确。

如果目标位置不是全0,则可以先用3.2.4的方式将其清零。

由于该功能较为常用,可以封装成函数/宏,调用时先将目标位置清零,然后填入指定的值:

uint32_t FillZeroBits(uint32_t number, size_t start, size_t count)
{
    return number & (~((~((~0) << count)) << start));
}


uint32_t SetBits(uint32_t number, uint32_t value, size_t start, size_t count)
{
    uint32_t result = FillZeroBits(number, start, count);
    return result | ((value & (~((~0) << count))) << start);
}

在这个示例函数中,还对value值进行了count位的裁剪,以防误输入过大的value导致其他位被意外篡改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小朋友的大哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值