# not - c++ operator

## 你如何設置,清除和切換一個位? (18)

`1`並不總是足夠寬

`x`對於`1 << x`導致未定義行為（UB）的轉變可能太大了。即使`x`不是太大，`~`也可能無法翻轉足夠多的重要位。

``````// 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
``````

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

``````number |= (type_of_number)1 << x;
``````

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

# 設置一下

``````number |= 1UL << n;
``````

# 清理一下

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

# 切換了一下

XOR運算符（ `^` ）可用於切換位。

``````number ^= 1UL << n;
``````

# 檢查一下

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

# 將第n位更改為x

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

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

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

## 檢查任意類型變量中任意位置的位：

``````#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;
}
``````

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);
}
``````

``````//  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;
}
}
``````

``````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;
``````

``````foo = foo | 001b
``````

``````if ( foo & 001b ) ....
``````

``````foo = foo & 110b
``````

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

struct bits mybits;
``````

``````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
``````

``````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;
}
``````

``````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)
``````

`|` operator：設置位

``````0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
``````

``````/* 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_CHECK_ALL(x,y) (((x) & (y)) == (y))   // warning: evaluates y twice
``````

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

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

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

return num;
}
``````

``````{
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);
}
}
}
``````

``````int value, pos;
``````

value - 數據

``````value = value | 1 << pos;
``````

``````value = value & ~(1 << pos);
``````

``````value = value ^ 1 << pos;
``````

``````#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, &)) ...
``````

``````#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;
}
``````

``````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);
}
``````