设置/取消单个位的简单方法

20

目前我正在使用以下代码来在字节中设置/取消单独的位:

if (bit4Set)
   nbyte |= (1 << 4);
else
   nbyte &= ~(1 << 4);

但是,你不能用更简单/优雅的方式来实现吗?比如一次操作中设置或取消位(bit)?

注意:我知道我可以编写一个函数来实现这个功能,但我想知道是否有更好的方式。


4
如何在C语言中设置、清除和切换单个位?要设置一个位,可以使用按位或运算符(|)将该位置为1,例如:flags |= 1 << bit_pos;要清除一个位,可以使用按位与运算符(&)将该位置为0,例如:flags &= ~(1 << bit_pos);要切换一个位,可以使用按位异或运算符(^)将该位取反,例如:flags ^= 1 << bit_pos; - obelix
4
@obelix: 这就是在所有琐碎问题都已经被回答之前的Stack Overflow吗?+112/+241, 90个收藏?伟大的问题/伟大的答案金徽章? - Nordic Mainframe
6个回答

15
当然可以!如果您在代码中展开|=&=,那么这将更加明显,但您可以编写如下代码:
nbyte = (nbyte & ~(1<<4)) | (bit4Set<<4);

请注意,bit4Set必须为零或,而不是任何非零值,才能使此操作正常工作。


取消设置,然后根据bit4set设置。我还没有想到这个。谢谢。 - djeidot
7
nbyte = (nbyte & ~(1<<4)) | ((!!bit4Set) << 4) 的作用是处理 bit4Set 不为零或一的情况。 - Alexandre C.

12

将它放在一个函数中,布尔类型将强制所有的bitval输入为0或1。

int change_bit(int val, int num, bool bitval)
{
    return (val & ~(1<<num)) | (bitval << num);
}

如果我把它放入一个函数中,我宁愿使用我写的代码。但是这样也没问题。 - djeidot
5
如果你在C++中让编译器将这个函数内联,那么它的速度就会像使用表达式本身一样快,同时还能获得更好的可读性加成。 - Nordic Mainframe

8
这是一个非常合理且完全标准的习语。

1
它可能会引入分支,从而影响性能。Pascal Cuoq的答案可能不太易读,但更高效。 - Nikola Malešević

5

您是否考虑过给位数分配助记符或标识符,而不是按数字引用它们?

举个例子,假设将第4位设置为启动核反应堆紧急停机。我们可以把它称为 INITIATE_SCRAM,而不是称之为“第4位”。以下是此代码的示例:

int const INITIATE_SCRAM = 0x10; // 1 << 4

...

if (initiateScram) {
    nbyte |= INITIATE_SCRAM;
} else {
    nbyte &= ~INITIATE_SCRAM;
}

这段代码在优化后不一定比你原来的代码更有效率,但我认为它更加清晰易懂,可能更易于维护。


这差不多是一样的东西。实际上我在使用标识符,只是在例子中没有把它们放进去。 - djeidot

1
nbyte |= (1 << 4);

如果赋值语句的右侧,(1 << 4),总是像这样一个常量,那么编译器可能会对其进行优化,使得生成的汇编代码更简单。
mov r0, _nbyte
mov r1, 10H         ; here is the optimization, no bit shift occured
or r0, r1
st _nbyte, r0

4
这是关于“如何设置nbyte的第4位”的答案。问题是:“根据bit4Set的值,如何设置或取消设置nbyte的第4位?” - Pascal Cuoq
1
谢谢。我误解了问题。我应该删除我的答案吗? - Donotalo
我会给这个答案点赞,因为即使它不完全切中要点,它也增加了额外的见解,就像帕斯卡尔的回答一样。 - TJ Bandrowsky

1
这个标记为C++,所以你考虑过使用std::bitset来代替自己进行所有的位操作吗?然后你可以通过数组表示法:bits[3] = bit4Set来设置相应的位。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接