Как установить, очистить и переключить бит?
Используйте оператор побитового ИЛИ (|
) для установки бита.
number |= 1UL << n;
Это установит n
-й бит числа number
. n
должно быть нулем, если вы хотите установить 1
-й бит и так далее до n-1
, если вы хотите установить n
-й бит.
Используйте 1ULL
, если число
шире, чем unsigned long
; продвижение 1UL << n
происходит только после оценки 1UL << n
, где смещение на ширину больше, чем ширина long
, является неопределенным поведением. То же самое относится и ко всем остальным примерам.
Для очистки бита используйте побитовый оператор AND (&
).
number &= ~(1UL << n);
Это очистит n
-й бит числа number
. Вы должны инвертировать битовую строку с помощью побитового оператора NOT (~
), а затем AND.
Для переключения бита можно использовать оператор XOR (^
).
number ^= 1UL << n;
Это переключит n
-й бит числа
.
Вы не просили об этом, но я мог бы добавить это.
Чтобы проверить бит, сдвиньте число n вправо, затем выполните побитовое И:
bit = (number >> n) & 1U;
Это поместит значение n
-го бита числа
в переменную bit
.
Установка n
-го бита в 1
или 0
может быть достигнута следующим образом на реализации 2's complement C++:
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
.
Также, как правило, не стоит копировать/вставлять код вообще, поэтому многие люди используют макросы препроцессора (например, ответ сообщества wiki далее) или что-то вроде инкапсуляции.
Используя стандарт C ++ библиотека: 'станд.:: bitset< N>';.
Или [Повышение] [2] версия: 'повышение:: 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.
[2]: http://en.wikipedia.org/wiki/Boost _ % 28C%2B%2B_libraries%29
Другой выбор состоит в том, чтобы использовать битовые поля:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
определяет 3 битовых поля (на самом деле, it' s три 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
Это только работает с битовыми полями фиксированного размера. Иначе Вы должны обратиться к методам битового жонглирования, описанным на предыдущих постах.
Я использую макрос, определенный в заголовочном файле, чтобы обращаться с набором сверл и ясный:
/* 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) {...}
для установки, очистки и проверки. Таким образом вы скрываете магические числа от остального кода.
В остальном я поддерживаю решение Джереми.
/*
** 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)))
Хорошо, let' s анализируют вещи...
Общее выражение, с которым у Вас, кажется, есть проблемы во всех них, является " (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' s с 1 в указанном положение. Единственная хитрая часть находится в BitClr () макрос, где мы должны установить единственные 0 битов в области 1' s. Это достигнуто при помощи 1' s дополнение того же выражения, как обозначено тильдой (~) оператор.
Как только маска создана it' s относился к аргументу, как Вы предполагаете, при помощи bitwise и (&), или (|), и xor (^) операторы. Начиная с маски имеет тип долго, макрос будет работать точно также над char' s, short' s, int' s, или long' s.
Итог - то, что это - общее решение всего класса проблемы. Это, конечно, возможное и даже соответствующее переписать эквивалентный из любого из них макрос с явной маской оценивает каждый раз Вас нужно один, но почему делают это? Помните, макро-замена происходит в препроцессор и так произведенный кодекс отразит то, что ценности считаются постоянными компилятором - т.е. it' s столь же эффективный, чтобы использовать обобщенный макрос относительно " перестройте wheel" каждый раз Вы должны сделать побитовая обработка.
Неубежденный? Here' 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
----[конец]-----------------------------------------------------------------
Используйте побитовые операторы: &``|
Чтобы установить последний бит в 000b
:
foo = foo | 001b
Проверить последний бит в foo
:
if ( foo & 001b ) ....
Чтобы очистить последний бит в foo
:
foo = foo & 110b
Я использовал XXXb
для наглядности. Возможно, вы будете работать с HEX-представлением, в зависимости от структуры данных, в которую вы упаковываете биты.
Для новичка я хотел бы объяснить немного больше с примером:
Пример:
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)
Here' s мой любимый разрядный арифметический макрос, который работает на любой тип неподписанного множества целого числа от 'неподписанной случайной работы' до '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, &)) ...
и т.д.
Поскольку это помечено " embedded" I' ll принимают you' ре используя микродиспетчера. Все вышеупомянутые предложения - действительный & работа («прочитанный изменяют, пишет», союзы, структуры, и т.д.).
Однако во время приступа основанной на осциллографе отладки я был поражен найти, что у этих методов есть значительное наверху в циклах центрального процессора по сравнению с написанием стоимости непосредственно к micro' s PORTnSET / реестры PORTnCLEAR, который вносит реальные изменения, где есть трудные петли / высокочастотный ISR' s toggling булавки.
Для незнакомых: В моем примере у микро есть общий государственный реестр булавки PORTn, который отражает булавки продукции, таким образом делая PORTn | =, результаты BIT_TO_SET в «прочитанный изменяют, пишут» тому регистру. Однако PORTnSET / реестры PORTnCLEAR берут ' 1' означать " пожалуйста, сделайте этот бит 1" (НАБОР) или " пожалуйста, сделайте этот бит zero" (ЯСНЫЙ) и ' 0' означать " оставьте булавку alone". таким образом Вы заканчиваете с двумя адресами порта, зависящими ли you' урегулирование ре или прояснение бита (не всегда удобный), но очень более быстрая реакция и меньший собранный кодекс.
У подхода bitfield есть другие преимущества во вложенной арене. Вы можете определить структуру, которая наносит на карту непосредственно на биты в конкретном регистре аппаратных средств.
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;
Вы должны знать, что бит упаковывает заказ - я думаю it' s 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 когда собранная Студия Солнца 8; I' ve также проверил его, используя MSVC ++ 2008 на amd64. It' s возможный сделать подобный макрос для урегулирования и прояснения битов. Основное отличие этого решения по сравнению со многими другими здесь - то, что оно работает на любое местоположение в в значительной степени любом типе переменной.
Более общий, для произвольных размерных битовых массивов:
#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);
}
}
}
Если you' ре, делающее большое битовое жонглирование, Вы могли бы хотеть использовать маски, которые сделают все это более быстрым. Следующие функции очень быстры и все еще гибки (они позволяют битовое жонглирование в битовых массивах любого размера).
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);
It' s до Вас, чтобы гарантировать, что разрядное число в диапазоне битового массива, который Вы передаете. Обратите внимание, что для небольших индийских процессоров, которые байты, слова, dwords, qwords, и т.д., наносят на карту правильно друг другу в памяти (главная причина, что небольшие индийские процессоры - ' better' чем процессоры тупоконечника, ах, я чувствую, что война пламени продвигается...).
Используйте это:
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;
}
У визуального 2010 C, и возможно многих других компиляторов, есть прямая поддержка встроенных битовых операций. Удивительно, это работает, даже '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 [я] =1', или 'IsGph [я] =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;
}
}
Примечание там - ничто " special" об этом кодексе. Это рассматривает немного как целое число - который технически, это. 1-битное целое число, которое может держать 2 ценности и 2 ценности только.
Я когда-то использовал этот подход, чтобы найти двойные отчеты ссуды, где loan_number был ключом ISAM, используя число ссуды с 6 цифрами в качестве индекса в разрядное множество. Жестоко быстро, и после 8 месяцев, доказал, что основная система, из которой мы получали данные, на самом деле работала со сбоями. Простота разрядных множеств делает уверенность в их правильности очень высоко - против ищущего подхода, например.
Используйте одного из операторов, как определено [здесь] (http://www.vantasyworld.com/articles/articles/36/article36_programming_bits.html).
Чтобы установить немного, использовал 'интервал x = x | 0x?'; где'?' позиция двоичного разряда в двухчастной форме.