2926

您如何设置、清除和切换位?

4

27 回答 27

4071

设置一点

使用按位或运算符 ( |) 设置位。

number |= 1UL << n;

这将设置的n第 th 位numbern应该为零,如果你想设置1st 位等等n-1,如果你想设置nth 位。

使用1ULLifnumberunsigned long; 直到在评估未定义行为的位置移动超过 a 的宽度之后,1UL << n才会发生提升。这同样适用于所有其余示例。1UL << nlong

清除一点

使用按位 AND 运算符 ( &) 清除位。

number &= ~(1UL << n);

这将清除 的n第 位number。您必须使用按位非运算符 ( ) 反转位字符串~,然后将其与。

切换一下

XOR 运算符 ( ^) 可用于切换位。

number ^= 1UL << n;

这将n切换number.

检查了一下

你没有要求这个,但我不妨添加它。

要检查一下,请将数字 n 向右移动,然后按位与它:

bit = (number >> n) & 1U;

这会将n第 th 位的值number放入变量bit中。

将第n位更改为x

n在 2 的补码 C++ 实现中,将第 th 位设置为10可以通过以下方式实现:

number ^= (-x ^ number) & (1UL << n);

如果是,则该位n将被设置,如果x1,则该位将x被清除0。如果x有其他价值,你会得到垃圾。 x = !!x会将其布尔化为 0 或 1。

要使其独立于 2 的补码否定行为(-1所有位都设置,与 1 的补码或符号/幅度 C++ 实现不同),请使用无符号否定。

number ^= (-(unsigned long)x ^ number) & (1UL << n);

或者

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

使用无符号类型进行可移植位操作通常是一个好主意。

或者

number = (number & ~(1UL << n)) | (x << n);

(number & ~(1UL << n))将清除第nth 位并将(x << n)nth 位设置为x

通常不要复制/粘贴代码通常也是一个好主意,因此很多人使用预处理器宏(如社区 wiki 回答进一步向下)或某种封装。

于 2008-09-07T00:50:45.403 回答
521

使用标准 C++ 库:std::bitset<N>.

Boost版本:boost::dynamic_bitset.

无需自己动手:

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<5> x;

    x[1] = 1;
    x[2] = 0;
    // Note x[0-4]  valid

    std::cout << x << std::endl;
}

[Alpha:] > ./a.out
00010

与标准库编译时大小的位集相比,Boost 版本允许运行时大小的位集。

于 2008-09-18T00:34:51.573 回答
271

另一种选择是使用位域:

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

定义一个 3 位字段(实际上是三个 1 位字段)。位操作现在变得有点(哈哈)简单:

设置或清除位:

mybits.b = 1;
mybits.c = 0;

稍微切换一下:

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

检查了一下:

if (mybits.c)  //if mybits.c is non zero the next line below will execute

这仅适用于固定大小的位字段。否则,您必须求助于之前文章中描述的位旋转技术。

于 2008-09-11T00:56:12.127 回答
228

我使用头文件中定义的宏来处理位设置和清除:

/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b))))        // '!!' to make sure this returns 0 or 1

#define BITMASK_SET(x, mask) ((x) |= (mask))
#define BITMASK_CLEAR(x, mask) ((x) &= (~(mask)))
#define BITMASK_FLIP(x, mask) ((x) ^= (mask))
#define BITMASK_CHECK_ALL(x, mask) (!(~(x) & (mask)))
#define BITMASK_CHECK_ANY(x, mask) ((x) & (mask))
于 2008-11-04T22:35:47.523 回答
132

有时值得使用 anenum命名这些位:

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

然后稍后使用这些名称。即写

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

设置、清除和测试。这样,您就可以从其余代码中隐藏幻数。

除此之外,我支持杰里米的解决方案。

于 2008-09-08T21:07:03.663 回答
52

来自snip-c.zip的 bitops.h:

/*
**  Bit set, clear, and test operations
**
**  public domain snippet by Bob Stout
*/

typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

好吧,我们来分析一下……

在所有这些中您似乎遇到问题的常见表达是“(1L <<(posn))”。所有这一切都是创建一个带有单个位的掩码,它适用于任何整数类型。“posn”参数指定您想要该位的位置。如果 posn==0,则此表达式的计算结果为:

0000 0000 0000 0000 0000 0000 0000 0001 binary.

如果 posn==8,它将评估为:

0000 0000 0000 0000 0000 0001 0000 0000 binary.

换句话说,它只是在指定位置创建一个 0 和 1 的字段。唯一棘手的部分是在 BitClr() 宏中,我们需要在 1 的字段中设置单个 0 位。这是通过使用波浪号 (~) 运算符表示的相同表达式的 1 补码来实现的。

创建掩码后,它会按照您的建议应用到参数,方法是使用按位和 (&)、或 (|) 和异或 (^) 运算符。由于掩码是 long 类型,因此宏在 char、short、int 或 long 上同样有效。

底线是,这是对一整类问题的通用解决方案。当然,每次需要时都可以使用显式掩码值重写任何这些宏的等效项,甚至是适当的,但为什么要这样做呢?请记住,宏替换发生在预处理器中,因此生成的代码将反映编译器认为这些值是常量这一事实 - 即,每次需要时使用通用宏与“重新发明轮子”一样有效做位操作。

不服气?这是一些测试代码 - 我使用 Watcom C 进行了全面优化,但没有使用 _cdecl,因此生成的反汇编将尽可能干净:

----[ TEST.C ]------------------------------------------ ----------------------

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

int bitmanip(int word)
{
      word = BitSet(word, 2);
      word = BitSet(word, 7);
      word = BitClr(word, 3);
      word = BitFlp(word, 9);
      return word;
}

----[ TEST.OUT(拆机)]-------------------------------------------------- ---------

Module: C:\BINK\tst.c
Group: 'DGROUP' CONST,CONST2,_DATA,_BSS

Segment: _TEXT  BYTE   00000008 bytes  
 0000  0c 84             bitmanip_       or      al,84H    ; set bits 2 and 7
 0002  80 f4 02                          xor     ah,02H    ; flip bit 9 of EAX (bit 1 of AH)
 0005  24 f7                             and     al,0f7H
 0007  c3                                ret     

No disassembly errors

----[ 完结 ]-------------------------------------------- ----------------------

于 2008-09-17T02:04:12.913 回答
39

对于初学者,我想用一个例子来解释一下:

例子:

value is 0x55;
bitnum : 3rd.

&运算符用于检查位:

0101 0101
&
0000 1000
___________
0000 0000 (mean 0: False). It will work fine if the third bit is 1 (then the answer will be True)

切换或翻转:

0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)

|运算符:设置位

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
于 2012-06-05T14:18:25.163 回答
27

这是我最喜欢的位算术宏,它适用于任何类型的无符号整数数组,从unsigned charsize_t(这是应该有效使用的最大类型):

#define BITOP(a,b,op) \
 ((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))

设置一点:

BITOP(array, bit, |=);

要清除一点:

BITOP(array, bit, &=~);

稍微切换一下:

BITOP(array, bit, ^=);

测试一下:

if (BITOP(array, bit, &)) ...

等等

于 2010-07-13T06:53:05.517 回答
27

由于这被标记为“嵌入式”,我假设您使用的是微控制器。以上所有建议都是有效且有效的(读取-修改-写入、联合、结构等)。

然而,在一次基于示波器的调试过程中,我惊讶地发现,与将值直接写入微控制器的 PORTnSET / PORTnCLEAR 寄存器相比,这些方法在 CPU 周期中具有相当大的开销,这在存在紧密循环/高电平的情况下产生了真正的差异-频率 ISR 的切换引脚。

对于那些不熟悉的人:在我的示例中,微控制器有一个反映输出引脚的通用引脚状态寄存器 PORTn,因此执行 PORTn |= BIT_TO_SET 会导致对该寄存器的读取-修改-写入。但是,PORTnSET / PORTnCLEAR 寄存器采用“1”表示“请将此位设为 1”(SET)或“请将此位设为 0”(CLEAR),而“0”表示“不要管该引脚”。因此,您最终会得到两个端口地址,具体取决于您是设置还是清除该位(并不总是方便),但反应更快,汇编代码更小。

于 2012-06-14T15:23:17.933 回答
25

位域方法在嵌入式领域还有其他优势。您可以定义一个直接映射到特定硬件寄存器中的位的结构。

struct HwRegister {
    unsigned int errorFlag:1;  // one-bit flag field
    unsigned int Mode:3;       // three-bit mode field
    unsigned int StatusCode:4;  // four-bit status code
};

struct HwRegister CR3342_AReg;

您需要注意位打包顺序 - 我认为它首先是 MSB,但这可能取决于实现。此外,验证您的编译器处理程序如何跨越字节边界。

然后,您可以像以前一样读取、写入、测试各个值。

于 2008-11-06T11:30:16.757 回答
20

检查任意类型变量中任意位置的位:

#define bit_test(x, y)  ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

示例用法:

int main(void)
{
    unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };

    for (int ix = 0; ix < 64; ++ix)
        printf("bit %d is %d\n", ix, bit_test(arr, ix));

    return 0;
}

注意: 这被设计为快速(考虑到它的灵活性)和非分支。在编译 Sun Studio 8 时,它会产生高效的 SPARC 机器代码;我还在 amd64 上使用 MSVC++ 2008 对其进行了测试。可以制作类似的宏来设置和清除位。与这里的许多其他解决方案相比,此解决方案的主要区别在于它适用于几乎任何类型的变量中的任何位置。

于 2009-01-03T23:44:14.293 回答
20

更一般地说,对于任意大小的位图:

#define BITS 8
#define BIT_SET(  p, n) (p[(n)/BITS] |=  (0x80>>((n)%BITS)))
#define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS)))
#define BIT_ISSET(p, n) (p[(n)/BITS] &   (0x80>>((n)%BITS)))
于 2009-06-13T21:27:39.243 回答
19

让我们先假设一些事情
num = 55是整数来执行按位操作(设置、获取、清除、切换)。
n = 4基于 0 的位位置执行按位运算。

如何获得一点?

  1. 为了获得nthnum 右移的位numn次。然后&与 1 执行按位与。
bit = (num >> n) & 1;

这个怎么运作?

       0011 0111 (55 in decimal)
    >>         4 (right shift 4 times)
-----------------
       0000 0011
     & 0000 0001 (1 in decimal)
-----------------
    => 0000 0001 (final result)

怎么设置一点?

  1. 设置特定的数字位。左移 1n次。然后|与 执行按位或运算num
num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

这个怎么运作?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     | 0011 0111 (55 in decimal)
-----------------
    => 0001 0000 (final result)

怎么清除一点?

  1. 左移 1n次,即1 << n.
  2. 对上述结果进行按位补码。这样第 n 位变为未设置,其余位变为设置,即~ (1 << n)
  3. 最后,&将上述结果与 进行位与运算num。以上三步加起来可以写成num & (~ (1 << n))

清除一点的步骤

num &= (~(1 << n));    // Equivalent to; num = num & (~(1 << n));

这个怎么运作?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
     ~ 0001 0000
-----------------
       1110 1111
     & 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

如何切换一点?

为了切换位,我们使用按位异或^运算符。如果两个操作数的对应位不同,则按位异或运算符计算为 1,否则计算为 0。

这意味着切换一个位,我们需要对要切换的位和 1 执行 XOR 操作。

num ^= (1 << n);    // Equivalent to; num = num ^ (1 << n);

这个怎么运作?

  • 如果要切换的位为 0,则0 ^ 1 => 1.
  • 如果要切换的位为 1,则1 ^ 1 => 0.
       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     ^ 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

推荐阅读——按位运算符练习

于 2019-06-10T05:52:54.873 回答
14

该程序是将任何数据位从 0 更改为 1 或从 1 更改为 0:

{
    unsigned int data = 0x000000F0;
    int bitpos = 4;
    int bitvalue = 1;
    unsigned int bit = data;
    bit = (bit>>bitpos)&0x00000001;
    int invbitvalue = 0x00000001&(~bitvalue);
    printf("%x\n",bit);

    if (bitvalue == 0)
    {
        if (bit == 0)
            printf("%x\n", data);
        else
        {
             data = (data^(invbitvalue<<bitpos));
             printf("%x\n", data);
        }
    }
    else
    {
        if (bit == 1)
            printf("elseif %x\n", data);
        else
        {
            data = (data|(bitvalue<<bitpos));
            printf("else %x\n", data);
        }
    }
}
于 2012-02-28T19:27:26.800 回答
12

如果你正在做很多事情,你可能想要使用掩码,这会使整个事情变得更快。以下函数非常快并且仍然很灵活(它们允许在任何大小的位图中进行位旋转)。

const unsigned char TQuickByteMask[8] =
{
   0x01, 0x02, 0x04, 0x08,
   0x10, 0x20, 0x40, 0x80,
};


/** Set bit in any sized bit mask.
 *
 * @return    none
 *
 * @param     bit    - Bit number.
 * @param     bitmap - Pointer to bitmap.
 */
void TSetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] |= TQuickByteMask[n];        // Set bit.
}


/** Reset bit in any sized mask.
 *
 * @return  None
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TResetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] &= (~TQuickByteMask[n]);    // Reset bit.
}


/** Toggle bit in any sized bit mask.
 *
 * @return   none
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TToggleBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] ^= TQuickByteMask[n];        // Toggle bit.
}


/** Checks specified bit.
 *
 * @return  1 if bit set else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitSet( short bit, const unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;    // Index to byte.
    n = bit % 8;    // Specific bit in byte.

    // Test bit (logigal AND).
    if (bitmap[x] & TQuickByteMask[n])
        return 1;

    return 0;
}


/** Checks specified bit.
 *
 * @return  1 if bit reset else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitReset( short bit, const unsigned char *bitmap)
{
    return TIsBitSet(bit, bitmap) ^ 1;
}


/** Count number of bits set in a bitmap.
 *
 * @return   Number of bits set.
 *
 * @param    bitmap - Pointer to bitmap.
 * @param    size   - Bitmap size (in bits).
 *
 * @note    Not very efficient in terms of execution speed. If you are doing
 *        some computationally intense stuff you may need a more complex
 *        implementation which would be faster (especially for big bitmaps).
 *        See (http://graphics.stanford.edu/~seander/bithacks.html).
 */
int TCountBits( const unsigned char *bitmap, int size)
{
    int i, count = 0;

    for (i=0; i<size; i++)
        if (TIsBitSet(i, bitmap))
            count++;

    return count;
}

请注意,要在 16 位整数中设置位“n”,请执行以下操作:

TSetBit( n, &my_int);

确保位数在您传递的位图范围内由您决定。请注意,对于字节、字、dword、qword 等在内存中正确映射到彼此的小端处理器(小端处理器比大端处理器“更好”的主要原因,啊,我感觉一场激烈的战争即将到来在...)。

于 2008-09-17T14:10:22.793 回答
12

用这个:

int ToggleNthBit ( unsigned char n, int num )
{
    if(num & (1 << n))
        num &= ~(1 << n);
    else
        num |= (1 << n);

    return num;
}
于 2009-04-11T23:05:16.580 回答
12

扩展bitset答案:

#include <iostream>
#include <bitset>
#include <string>

using namespace std;
int main() {
  bitset<8> byte(std::string("10010011");

  // Set Bit
  byte.set(3); // 10010111

  // Clear Bit
  byte.reset(2); // 10010101

  // Toggle Bit
  byte.flip(7); // 00010101

  cout << byte << endl;

  return 0;
}
于 2014-05-08T04:33:41.203 回答
12

如果您想在Linux 内核中使用 C 编程执行所有这些操作,那么我建议使用 Linux 内核的标准 API。

https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html

set_bit  Atomically set a bit in memory
clear_bit  Clears a bit in memory
change_bit  Toggle a bit in memory
test_and_set_bit  Set a bit and return its old value
test_and_clear_bit  Clear a bit and return its old value
test_and_change_bit  Change a bit and return its old value
test_bit  Determine whether a bit is set

注意:这里整个操作都是一步完成的。因此,即使在 SMP 计算机上,这些都保证是原子的,并且对于保持处理器之间的一致性很有用。

于 2016-05-27T16:41:15.503 回答
11

Visual C 2010,也许还有许多其他编译器,直接支持内置的布尔运算。一个位有两个可能的值,就像一个布尔值一样,所以我们可以使用布尔值来代替——即使它们占用的空间比此表示中的内存。这行得通,即使sizeof()操作员也能正常工作。

bool    IsGph[256], IsNotGph[256];

//  Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++)  {
    IsGph[i] = isgraph((unsigned char)i);
}

因此,对于您的问题,IsGph[i] =1IsGph[i] =0使设置和清除布尔值变得容易。

要查找不可打印的字符:

//  Initialize boolean array to detect UN-printable characters, 
//  then call function to toggle required bits true, while initializing a 2nd
//  boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++)  {
    if(IsGph[i])    {
         IsNotGph[i] = 0;
    }   else   {
         IsNotGph[i] = 1;
    }
}

请注意,此代码没有什么“特别”之处。它有点像整数 - 从技术上讲,确实如此。一个 1 位整数,可以保存 2 个值,并且只能保存 2 个值。

我曾经使用这种方法来查找重复的贷款记录,其中,loan_number 是 ISAM 键,使用 6 位贷款编号作为位数组的索引。速度非常快,8 个月后,证明我们从中获取数据的大型机系统实际上出现了故障。位数组的简单性使得对其正确性的信心非常高 - 例如与搜索方法相比。

于 2012-12-30T02:31:33.550 回答
7
int set_nth_bit(int num, int n){    
    return (num | 1 << n);
}

int clear_nth_bit(int num, int n){    
    return (num & ~( 1 << n));
}

int toggle_nth_bit(int num, int n){    
    return num ^ (1 << n);
}

int check_nth_bit(int num, int n){    
    return num & (1 << n);
}
于 2018-02-21T12:35:12.247 回答
5

以下是我使用的一些宏:

SET_FLAG(Status, Flag)            ((Status) |= (Flag))
CLEAR_FLAG(Status, Flag)          ((Status) &= ~(Flag))
INVALID_FLAGS(ulFlags, ulAllowed) ((ulFlags) & ~(ulAllowed))
TEST_FLAGS(t,ulMask, ulBit)       (((t)&(ulMask)) == (ulBit))
IS_FLAG_SET(t,ulMask)             TEST_FLAGS(t,ulMask,ulMask)
IS_FLAG_CLEAR(t,ulMask)           TEST_FLAGS(t,ulMask,0)
于 2015-02-06T23:11:18.143 回答
4

您如何设置、清除和切换单个位?

在尝试形成掩码时解决常见的编码缺陷:
1并不总是足够宽

number当类型比 更宽时会出现什么问题1?对于导致未定义行为(UB)
x的转变可能太大了。即使不是太大,也可能不会翻转足够多的最高有效位。1 << xx~

// assume 32 bit int/unsigned
unsigned long long number = foo();

unsigned x = 40; 
number |= (1 << x);  // UB
number ^= (1 << x);  // UB
number &= ~(1 << x); // UB

x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough

确保 1 足够宽:

代码可以使用1ull或迂腐(uintmax_t)1,让编译器优化。

number |= (1ull << x);
number |= ((uintmax_t)1 << x);

或演员表 - 这会导致编码/审查/维护问题保持演员表正确和最新。

number |= (type_of_number)1 << x;

或者1通过强制一个至少与number.

number |= (number*0 + 1) << x;

与大多数位操作一样,最好使用无符号类型而不是有符号类型

于 2017-09-27T18:18:48.873 回答
4

该程序基于@Jeremy 的上述解决方案。如果有人想快速玩耍。

public class BitwiseOperations {

    public static void main(String args[]) {

        setABit(0, 4); // set the 4th bit, 0000 -> 1000 [8]
        clearABit(16, 5); // clear the 5th bit, 10000 -> 00000 [0]
        toggleABit(8, 4); // toggle the 4th bit, 1000 -> 0000 [0]
        checkABit(8,4); // check the 4th bit 1000 -> true 
    }

    public static void setABit(int input, int n) {
        input = input | ( 1 << n-1);
        System.out.println(input);
    }


    public static void clearABit(int input, int n) {
        input = input & ~(1 << n-1);
        System.out.println(input);
    }

    public static void toggleABit(int input, int n) {
        input = input ^ (1 << n-1);
        System.out.println(input);
    }

    public static void checkABit(int input, int n) {
        boolean isSet = ((input >> n-1) & 1) == 1; 
        System.out.println(isSet);
    }
}


Output :
8
0
0
true
于 2020-04-22T20:30:38.773 回答
3

支持更改多个位的模板版本(放在头文件中)(顺便说一句,适用于 AVR 微控制器):

namespace bit {
  template <typename T1, typename T2>
  constexpr inline T1 bitmask(T2 bit) 
  {return (T1)1 << bit;}
  template <typename T1, typename T3, typename ...T2>
  constexpr inline T1 bitmask(T3 bit, T2 ...bits) 
  {return ((T1)1 << bit) | bitmask<T1>(bits...);}

  /** Set these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void set (T1 &variable, T2 ...bits) 
  {variable |= bitmask<T1>(bits...);}
  /** Set only these bits (others will be cleared) */
  template <typename T1, typename ...T2>
  constexpr inline void setOnly (T1 &variable, T2 ...bits) 
  {variable = bitmask<T1>(bits...);}
  /** Clear these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void clear (T1 &variable, T2 ...bits) 
  {variable &= ~bitmask<T1>(bits...);}
  /** Flip these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void flip (T1 &variable, T2 ...bits) 
  {variable ^= bitmask<T1>(bits...);}
  /** Check if any of these bits are set */
  template <typename T1, typename ...T2>
  constexpr inline bool isAnySet(const T1 &variable, T2 ...bits) 
  {return variable & bitmask<T1>(bits...);}
  /** Check if all these bits are set */
  template <typename T1, typename ...T2>
  constexpr inline bool isSet (const T1 &variable, T2 ...bits) 
  {return ((variable & bitmask<T1>(bits...)) == bitmask<T1>(bits...));}
  /** Check if all these bits are not set */
  template <typename T1, typename ...T2>
  constexpr inline bool isNotSet (const T1 &variable, T2 ...bits) 
  {return ((variable & bitmask<T1>(bits...)) != bitmask<T1>(bits...));}
}

使用示例:

#include <iostream>
#include <bitset> // for console output of binary values

// and include the code above of course

using namespace std;

int main() {
  uint8_t v = 0b1111'1100;
  bit::set(v, 0);
  cout << bitset<8>(v) << endl;

  bit::clear(v, 0,1);
  cout << bitset<8>(v) << endl;

  bit::flip(v, 0,1);
  cout << bitset<8>(v) << endl;

  bit::clear(v, 0,1,2,3,4,5,6,7);
  cout << bitset<8>(v) << endl;

  bit::flip(v, 0,7);
  cout << bitset<8>(v) << endl;
}

顺便说一句:事实证明,如果不将优化器参数(例如:-O3)发送到编译器,则不会使用 constexpr 和 inline。随意尝试https://godbolt.org/上的代码并查看 ASM 输出。

于 2018-02-10T20:07:16.110 回答
2

这是 C 中执行基本按位运算的例程:

#define INT_BIT (unsigned int) (sizeof(unsigned int) * 8U) //number of bits in unsigned int

int main(void)
{
    
    unsigned int k = 5; //k is the bit position; here it is the 5th bit from the LSb (0th bit)
    
    unsigned int regA = 0x00007C7C; //we perform bitwise operations on regA
    
    regA |= (1U << k);    //Set kth bit
    
    regA &= ~(1U << k);   //Clear kth bit
    
    regA ^= (1U << k);    //Toggle kth bit
    
    regA = (regA << k) | regA >> (INT_BIT - k); //Rotate left by k bits
    
    regA = (regA >> k) | regA << (INT_BIT - k); //Rotate right by k bits

    return 0;   
}

于 2021-03-17T05:14:54.130 回答
0

将第 n 位设置为 x(位值)而不使用 -1

有时当您不确定 -1 或类似结果会导致什么时,您可能希望设置第 n 位而不使用 -1:

number = (((number | (1 << n)) ^ (1 << n))) | (x << n);

说明:((number | (1 << n)将第 n 位设置为 1(其中|表示按位或),然后(...) ^ (1 << n)我们将第 n 位设置为 0,最后将(...) | x << n)我们设置为 0 的第 n 位设置为 (bit value) x

这也适用于golang.

于 2021-02-06T09:43:22.130 回答
-2

在 C 语言中尝试以下函数之一来更改 n 位:

char bitfield;

// Start at 0th position

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}

或者

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}

或者

void chang_n_bit(int n, int value)
{
    if(value)
        bitfield |= 1 << n;
    else
        bitfield &= ~0 ^ (1 << n);
}

char get_n_bit(int n)
{
    return (bitfield & (1 << n)) ? 1 : 0;
}
于 2014-05-27T11:46:39.147 回答