Как вы устанавливаете, очищаете и переключаете один бит?

Как вы устанавливаете, очищаете и немного переключаетесь?

Ответ 1

Установка немного

Используйте побитовый оператор ИЛИ (|), чтобы установить бит.

number |= 1UL << n;

Это установит n й бит number. n-1 n должно быть равно нулю, если вы хотите установить 1 й бит и т.д. до n-1, если вы хотите установить n й бит.

Используйте 1ULL если number шире, чем unsigned long; продвижение 1UL << n не происходит до тех пор, пока после оценки 1UL << n не будет определено поведение, 1UL << n более чем на ширину long. То же самое относится ко всем остальным примерам.

Прояснение немного

Используйте побитовый оператор И (&), чтобы очистить немного.

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

Это очистит n й бит number. Вы должны инвертировать битовую строку с помощью побитового оператора NOT (~), затем AND it.

Немного переключаясь

Оператор XOR (^) может быть использован для переключения немного.

number ^= 1UL << n;

Это переключит n й бит number.

Немного проверяя

Вы не просили об этом, но я мог бы также добавить это.

Чтобы проверить немного, сдвиньте число n вправо, затем поразрядно И это:

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

Это поместит значение n го бита number в переменный bit.

Изменение n-го бита на x

Установка n го бита в 1 или 0 может быть достигнута с помощью следующего в реализации C++ с 2 дополнениями:

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

Бит n будет установлен, если x равен 1, и очищен, если 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)) очистит n й бит, а (x << n) установит n й бит на x.

Как правило, это хорошая идея, чтобы вообще не копировать/вставлять код, и поэтому многие люди используют макросы препроцессора (например, ответ вики сообщества ниже) или инкапсуляцию.

Ответ 2

Использование стандартной библиотеки 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 позволяет устанавливать бит-бит по размеру по сравнению со стандартным битрейтом.

Ответ 3

Другой вариант - использовать битовые поля:

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

struct bits mybits;

определяет 3-битное поле (на самом деле это три однобитовых поля). Бит-операции теперь становятся немного (ха-ха) проще:

Чтобы установить или очистить бит:

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

Это работает только с битовыми полями фиксированного размера. В противном случае вам придется прибегнуть к методам бит-скручивания, описанным в предыдущих сообщениях.

Ответ 4

Я использую макросы, определенные в файле заголовка, для обработки набора бит и очистки:

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

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (((x) & (y)) == (y))   // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))

Ответ 5

Иногда стоит использовать enum для обозначения битов:

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

Затем используйте имена позже. То есть написать

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

установить, очистить и проверить. Таким образом вы скрываете магические числа от остальной части вашего кода.

Кроме того, я поддерживаю решение Джереми.

Ответ 6

Из 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(), где нам нужно установить один бит 0 в поле 1. Это достигается с помощью дополнения 1 того же выражения, которое обозначено оператором тильда (~).

После того как маска создана, она применяется к аргументу, как вы предлагаете, используя побитовые операторы и (&), или (|), и xor (^). Поскольку маска имеет тип 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

---- [finis] ------------------------------------------- ----------------------

Ответ 7

Используйте побитовые операторы: & |

Чтобы установить последний бит в 000b:

foo = foo | 001b

Чтобы проверить последний бит в foo:

if ( foo & 001b ) ....

Чтобы очистить последний бит в foo:

foo = foo & 110b

Для ясности я использовал XXXb. Вероятно, вы будете работать с представлением HEX, в зависимости от структуры данных, в которой вы упаковываете биты.

Ответ 8

Для новичка я хотел бы еще немного пояснить пример:

Пример:

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)

Ответ 9

Здесь мой любимый битовый арифметический макрос, который работает для любого типа беззнакового целочисленного массива от unsigned char до size_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, &)) ...

и др.

Ответ 10

Прикладной подход имеет другие преимущества во встроенной арене. Вы можете определить структуру, которая непосредственно сопоставляется с битами в конкретном регистре оборудования.

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, но это может быть зависимым от реализации. Кроме того, проверьте, как поля обработчиков ваших обработчиков пересекают границы байтов.

Затем вы можете читать, писать, тестировать отдельные значения, как и раньше.

Ответ 11

Поскольку это помечено как "встроенное", я предполагаю, что вы используете микроконтроллер. Все приведенные выше предложения действительны и работают (read-modify-write, union, structs и т.д.).

Однако во время оспаривания на основе осциллографа я был поражен, обнаружив, что эти методы имеют значительные накладные расходы в цикле процессора по сравнению с записью значения непосредственно в регистры micro PORTnSET/PORTnCLEAR, что делает реальную разницу там, где есть петли/высокочастотные переключающие контакты ISR.

Для тех, кто не знаком: В моем примере микро имеет общий регистр PORTn, который отображает выходные выводы, поэтому PORTn | = BIT_TO_SET приводит к чтению-изменению-записи в этот регистр. Однако регистры PORTnSET/PORTnCLEAR принимают значение "1", чтобы означать "пожалуйста, сделайте этот бит 1" (SET) или "пожалуйста, сделайте этот бит ноль" (CLEAR) и "0", чтобы означать "оставьте один вывод". поэтому вы получаете два порта, в зависимости от того, устанавливаете ли вы или очищаете бит (не всегда удобно), но гораздо быстрее реагируете и уменьшаете собранный код.

Ответ 12

Проверьте бит в произвольном месте в переменной произвольного типа:

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

Примечания: Это спроектировано так, чтобы быть быстрым (учитывая его гибкость) и не разветвленным. Это приводит к эффективному программному коду SPARC при компиляции Sun Studio 8; Я также тестировал его с помощью MSVС++ 2008 на amd64. Можно создать аналогичные макросы для установки и очистки бит. Ключевое отличие этого решения по сравнению со многими другими здесь заключается в том, что он работает для любого местоположения практически в любом типе переменных.

Ответ 13

Более общие для растровых изображений произвольного размера:

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

Ответ 14

Если вы делаете много бит, вы можете использовать маски, которые ускорят все это. Следующие функции очень быстрые и по-прежнему гибкие (они позволяют свертывание бит в битовых картах любого размера).

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

Обратите внимание: для установки бит 'n' в 16-битном целое вы делаете следующее:

TSetBit( n, &my_int);

Это зависит от вас, чтобы убедиться, что номер бит находится в пределах диапазона бит-карты, которую вы передаете. Обратите внимание, что для маленьких процессоров endian, которые байты, слова, слова, слова и т.д. Правильно отображают друг друга в памяти (основная причина, по которой маленькие процессоры endian лучше, чем процессоры большого числа, ах, я чувствую, что начинается пламенная война на...).

Ответ 15

Эта программа предназначена для изменения любого бита данных от 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);
        }
    }
}

Ответ 16

Используйте это:

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

    return num;
}

Ответ 17

Расширение ответа 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;
}

Ответ 18

Если вы хотите выполнить эту операцию с программированием на языке C в ядре Linux, я предлагаю использовать стандартные API ядра Linux.

См. 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-компьютерах и полезны для обеспечения согласованности между процессорами.

Ответ 19

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] =1 или IsGph[i] =0 упрощают настройку и очистку bools.

Чтобы найти непечатаемые символы:

//  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 месяцев доказали, что система мэйнфреймов, с которой мы получали данные, действительно работала неправильно. Простота битовых массивов делает уверенность в их правильности очень высокой - по сравнению с поисковым подходом, например.

Ответ 20

Используйте один из операторов, как определено здесь.

Чтобы установить бит, используйте int x = x | 0x?;, где ? - это битовая позиция в двоичной форме.

Ответ 21

Вот некоторые макросы, которые я использую:

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)

Ответ 22

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

Ответ 23

Переменная используется

int value, pos;

значение - данные
pos - позиция бита, который нам интересно установить, очистить или переключить.

Установить немного:

value = value | 1 << pos;

Очистить немного:

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

Переключить немного:

value = value ^ 1 << pos;

Ответ 24

Как вы устанавливаете, очищаете и переключаете один бит?

Чтобы решить проблему с общей ошибкой кодирования при попытке сформировать маску:
1 не всегда достаточно широко

Какие проблемы возникают, когда number является более широким типом, чем 1?
x может быть слишком большим для сдвига 1 << x, приводящего к поведению undefined (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

Застраховать 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;

Как и большинство манипуляций с битами, лучше всего работать с неподписанными типами, а не с подписанными

Ответ 25

Шаблонная версия С++ 11 (помещается в заголовок):

namespace bit {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bit) {variable |=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bit) {variable ^=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);}
}

namespace bitmask {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bits) {variable |= bits;}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bits) {variable &= ~bits;}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bits) {variable ^= bits;}
    template <typename T1, typename T2> inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);}
    template <typename T1, typename T2> inline bool test_any(T1 &variable, T2 bits) {return variable & bits;}
}

Ответ 26

  Предположим сначала несколько вещей
num = 55 Целочисленное значение для выполнения побитовых операций (установка, получение, очистка, переключение).
n = 4 0 битовая позиция для выполнения побитовых операций.

Как получить немного?

  1. Чтобы получить nth бит num смещения вправо num, n раз. Затем выполните побитовое И & с 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. Чтобы установить конкретный бит числа. Сдвиг влево 1 n раз. Затем выполните побитовую операцию ИЛИ | с 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. Сдвиг влево 1, n раз, т.е. 1 << n.
  2. Выполните побитовое дополнение с вышеуказанным результатом. Так что n-й бит становится неустановленным, а остаток бита становится установленным, т.е. ~ (1 << n).
  3. Наконец, выполните побитовую операцию И & с указанным выше результатом и num. Вышеупомянутые три шага вместе можно записать как num & (~ (1 << n));

Steps to clear a bit

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)

Как немного переключиться?

Чтобы переключить немного, мы используем побитовый оператор XOR ^. Побитовый оператор XOR оценивается в 1, если соответствующие биты обоих операндов различны, в противном случае - в 0.

Что означает переключение немного, нам нужно выполнить операцию XOR с битом, который вы хотите переключить, и 1.

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)

Рекомендуемое чтение - Битовые упражнения оператора

Ответ 27

Попробуйте одну из этих функций на языке 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;
}

Ответ 28

Для установки BitIdx -th бит в Number на BitValue

Number = Number xor (1 shl BitIdx) or (BitValue shl BitIdx)

Трюк здесь заключается в том, чтобы сначала безоговорочно очистить BitIdx -th бит, указав его с помощью 1. Эта версия выглядит несколько медленнее, чем с ветвлением (if bit = 1 then setbit else clearbit), но является однострочным.