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

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

34 ответа

Решение

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

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

number |= 1UL << n;

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

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

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

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

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

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

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

Оператор 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 или знаком / величиной), использует отрицание без знака.

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,

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

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

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

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

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

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

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

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

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

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

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

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

Кроме этого я одобряю решение Джереми.

Из snop-c.zip's 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] ------------------------------------------- ----------------------

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

Пример:

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)

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

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

foo = foo | 001b

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

if ( foo & 001b ) ....

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

foo = foo & 110b

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

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

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

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

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

и т.п.

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

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

  1. Чтобы получить nth бит числа сдвиг вправо 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. Чтобы установить конкретный бит числа. Левый сдвиг 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. Левый сдвиг 1, n раз т.е. 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)

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

Чтобы немного переключиться, мы используем побитовое 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)

Рекомендуемая литература - упражнения для побитовых операторов

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

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

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

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

#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; Я также проверил это, используя MSVC++ 2008 на amd64. Можно сделать аналогичные макросы для установки и очистки битов. Ключевое отличие этого решения по сравнению со многими другими здесь заключается в том, что оно работает для любого местоположения практически во всех типах переменных.

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

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

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

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

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

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

Использовать этот:

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

    return num;
}

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

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

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

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

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

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

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

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

Какие проблемы случаются, когда number это более широкий тип, чем 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

Чтобы застраховать 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;

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

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

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)

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

int value, pos;

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

value = value | 1 << pos;

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

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

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

value = value ^ 1 << pos;

Эта программа основана на вышеупомянутом решении @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

Шаблонная версия C++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;}
}

Вот процедура на 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;   
}

В Java с помощью BitSet (java.util.BitSet) класс может быть полезным. Также есть часто используемые методы. Когда требуется обработка битов и не известен верхний предел, использование BitSet может оказаться хорошим выбором.

Для номера как объекта BitSet.
Вы можете,

Установите конкретный бит

number.set(indexOfTargetedBit)

Очистить конкретный бит

number.clear(indexOfTargetedBit)

Переключить конкретный бит

number.flip(indexOfTargetedBit)

Вы можете получить более подробную информацию о BitSet здесь

Установить, проверить, сбросить или перевернуть бит в i-й позиции

      set bit      :    S |= (1<<i)
check bit    :    S & (1<<i)
clear bit    :    S &= ~(1<<i)
flip bit     :    S ^= ~(1<<i)

Ссылка: Bitwise Hacks!

Другие вопросы по тегам