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

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

2391
задан JL2210 22 August 2019 в 19:43
поделиться

12 ответов

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

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

number |= 1UL << n;

, Который установит n th бит [1 110]. n должен быть нуль, если Вы хотите установить 1, стоун укусил и так далее [до 1 113], если Вы хотите установить n, th укусил.

Использование 1ULL, если number более широко, чем [1 117]; продвижения [1 118] не происходит до окончания оценки 1UL << n, где это - неопределенное поведение сместиться больше, чем ширина long. То же относится ко всей остальной части примеров.

Очистка немного

Использование поразрядная операция И (&) для очистки немного.

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

, Который очистится n th бит [1 123]. Необходимо инвертировать строку битов с оператором (~) битового "НЕ", тогда И этим.

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

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

number ^= 1UL << n;

, Который переключится n th бит [1 127].

Проверка немного

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

Для проверки немного сместите номер n направо, тогда поразрядно И это:

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

, Который поместит значение n th бит [1 129] в переменную bit.

Изменение nth укусил к [1 149] x

Установка n, th укусил или к [1 132] или к 0, может быть достигнут со следованием 2's дополнительная реализация C++:

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

Бит n будет установлен, если x будет 1, и очищен, если x 0. Если x имеет некоторое другое значение, Вы получаете мусор. x = !!x будет booleanize это к 0 или 1.

Для создания этого независимого политика 2's дополнительное поведение отрицания (где -1 имеет весь набор битов, в отличие от этого, на 1's дополнение или реализация 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, th укусил, и (x << n) установит n, th укусил к [1 146].

Это - также обычно хорошая идея не скопировать/вставить кодировать в целом, и столько людей использует макросы препроцессора (как [1 147] сообщество ответ Wiki далее вниз ) или своего рода инкапсуляция.

3373
ответ дан Helping Bean 22 August 2019 в 19:43
поделиться

Другая опция состоит в том, чтобы использовать битовые поля:

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

struct bits mybits;

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

, Чтобы установить или очиститься немного:

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

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

230
ответ дан Ferruccio 22 August 2019 в 19:43
поделиться

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

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

Тогда используют имена позже. Т.е. запишите

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

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

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

110
ответ дан jfs 22 August 2019 в 19:43
поделиться

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

Для установки последнего бита в 000b:

foo = foo | 001b

Для проверки последнего бита в foo:

if ( foo & 001b ) ....

Для очистки последнего бита в foo:

foo = foo & 110b

я использовал XXXb для ясности. Вы будете, вероятно, работать с ШЕСТНАДЦАТЕРИЧНЫМ представлением, в зависимости от структуры данных, в которой Вы упаковываете биты.

36
ответ дан Azeem 22 August 2019 в 19:43
поделиться
  • 1
    Rory, спасибо за это четкое и глубокое объяснение, которое действительно дало форму различному возможному выбору. – Ronnie 4 October 2009 в 10:49

Пользование Стандартной Библиотекой C++: std::bitset<N> .

Или Повышение версия: 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

версия Повышения позволяет измеренный bitset времени выполнения по сравнению с стандартная библиотека , время компиляции измерило bitset.

434
ответ дан Peter Mortensen 22 August 2019 в 19:43
поделиться

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

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

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

13
ответ дан Tim Ring 22 August 2019 в 19:43
поделиться

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

, Как только маска создается, она относилась к аргументу, как Вы предполагаете, при помощи поразрядного и (&), или (|), и xor (^) операторы. Так как маска имеет тип долго, макросы будут работать точно также над символом, short's, интервалом или long's.

нижняя строка - то, что это - общее решение всего класса проблем. Это является, конечно, возможным и даже соответствующим переписать эквивалент какого-либо из них, макросы с явной маской оценивают каждый раз, когда Вам нужно один, но почему делают это? Помните, макроподстановка происходит в препроцессоре и таким образом, сгенерированный код отразит то, что значения считает постоянными компилятор - т.е. столь же эффективно использовать обобщенные макросы для "перестраивания колеса", каждый раз необходимо сделать побитовую обработку.

Неубежденный? Вот некоторый тестовый код - я использовал 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

--------------------------------------------------------------------

43
ответ дан Felipe Augusto 22 August 2019 в 19:43
поделиться
  • 1
    Бог чертовски, который является очень полезным ответом. Спасибо за совместное использование, что Вы знаете. – Dan Rosenstark 16 February 2010 в 00:58

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

/* 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))
158
ответ дан 4 revs, 3 users 77% 22 August 2019 в 19:43
поделиться

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

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

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

23
ответ дан Roddy 22 August 2019 в 19:43
поделиться
  • 1
    Rory, не, что я имею какое-либо отношение к Мобильному Dev в настоящее время, но мне просто, хотел приветствовать Вашего Входного человека, таким образом правильно написанный и логический поток выше, необходимо быть участником дебатов:) – DevMania 26 August 2011 в 06:35

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

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

19
ответ дан John Zwinck 23 August 2019 в 05:43
поделиться
  • 1
    Используя MonoTouch к " сварите деревянный bookcase" похож на наличие сварщика, которого Вы уже знаете для использования, но это волшебно кует, завинчивает и склеивает книжный шкаф без того, что вы имели необходимость знать о деталях. Вы можете закапывать и выяснять Вашего нового волшебного сварщика, но Вас don' t имеют к. Если Ваша цель состоит в том, чтобы создать или зафиксировать книжный шкаф, и если все, что Вы знаете, является сварочным, то... эй - идут для него. Некоторые люди хотят узнать все о механизме - некоторые просто хотят создать вещи. С MonoTouch можно сделать обоих (MT учил меня [еще 111] о Apple' s стопка инструмента - that' s потрясающий). Попробуйте его перед стуком его:) – Rory Blyth 3 November 2009 в 06:38

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

#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)))
20
ответ дан 22 November 2019 в 19:55
поделиться

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

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

    return num;
}
12
ответ дан 22 November 2019 в 19:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: