Как вы устанавливаете, очищаете и переключаете один бит?
Как вы устанавливаете, очищаете и немного переключаетесь?
Ответы
Ответ 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
/*
** 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 битовая позиция для выполнения побитовых операций.
Как получить немного?
- Чтобы получить
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
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,
n
раз, т.е. 1 << n
.
- Выполните побитовое дополнение с вышеуказанным результатом. Так что n-й бит становится неустановленным, а остаток бита становится установленным, т.е.
~ (1 << n)
.
- Наконец, выполните побитовую операцию И
&
с указанным выше результатом и 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)
Рекомендуемое чтение - Битовые упражнения оператора
Ответ 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
), но является однострочным.