Biraz nasıl ayarlar, temizler ve değiştirirsiniz?
Biraz nasıl ayarlar, temizler ve değiştirirsiniz?
Yanıtlar:
|
Bir bit ayarlamak için bitsel VEYA operatörünü ( ) kullanın.
number |= 1UL << n;
Bu n
th bitini ayarlayacaktır number
. st bitini n
ayarlamak istiyorsanız sıfır olmalı 1
ve bu biti n-1
ayarlamak istiyorsanız, eğer n
bit bitini ayarlamak istiyorsanız .
Kullanım 1ULL
durumunda number
daha geniş olduğu unsigned long
; 'nin tanıtımı, a'nın genişliğinden daha fazla kaymanın tanımlanmamış davranışının nerede 1UL << n
değerlendirildiğine kadar gerçekleşmez . Aynısı tüm diğer örnekler için de geçerlidir.1UL << n
long
&
Biraz temizlemek için bitsel AND operatörünü ( ) kullanın.
number &= ~(1UL << n);
Bu n
biraz temizleyecek number
. Bit dizesini bitsel DEĞİL operatörü ( ~
) ile ve sonra AND ile ters çevirmelisiniz .
XOR işleci ( ^
) biraz geçiş yapmak için kullanılabilir.
number ^= 1UL << n;
Bu n
inci biraz geçiş yapacak number
.
Bunu siz istemediniz, ama ben de ekleyebilirim.
Biraz kontrol etmek için, n sayısını sağa, sonra bitsel olarak kaydırın VE:
bit = (number >> n) & 1U;
Bu, n
th bitinin değerini number
değişkene koyacaktır bit
.
2 n
bit'in tamamlayıcı C ++ uygulamasında th bit'inin ikisine ya 1
da 0
aşağıdaki şekilde ayarlanması sağlanabilir:
number ^= (-x ^ number) & (1UL << n);
Bit n
eğer kurulacak x
olan 1
ve eğer temizlenir x
olduğunu 0
. x
Başka bir değeri varsa , çöp alırsınız. x = !!x
0 veya 1 olarak booleanize eder.
Bunu 2'nin tamamlayıcı olumsuzlama davranışından bağımsız hale getirmek için ( -1
1'in tamamlayıcısı veya işaret / büyüklük C ++ uygulamasından farklı olarak, tüm bitlerin ayarlandığı yer) imzasız olumsuzlama kullanın.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
veya
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
Taşınabilir bit manipülasyonu için imzasız tipler kullanmak genellikle iyi bir fikirdir.
veya
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
temizleyecektir n
inci biti ve (x << n)
ayarlayacaktır n
için inci biti x
.
Genel olarak kodu kopyalamamak / yapıştırmamak da genellikle iyi bir fikirdir ve birçok kişi önişlemci makrolarını ( topluluk wiki'sinin daha da aşağıya cevabı gibi ) veya bir tür kapsüllemeyi kullanır.
bit = (number >> x) & 1
1
int
imzalanmış bir değişmez değerdir. Dolayısıyla, buradaki tüm işlemler standartlar tarafından iyi tanımlanmamış işaretli numaralar üzerinde çalışır. Standartlar ikisinin tamamlayıcı veya aritmetik kaymasını garanti etmez, bu nedenle kullanımı daha iyidir 1U
.
number = number & ~(1 << n) | (x << n);
n'inci biti x olarak değiştirmeyi tercih ederim .
Standart C ++ Kitaplığı kullanma: std::bitset<N>
.
Veya Boost versiyonu: boost::dynamic_bitset
.
Kendinizi yuvarlamanıza gerek yok:
#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 sürümü, standart bir kitaplık derleme zamanı boyutlu bit kümesine kıyasla çalışma zamanı boyutlu bir bit kümesine izin verir .
Diğer seçenek bit alanlarını kullanmaktır:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
3 bitlik bir alanı tanımlar (aslında, üç tane 1 bitlik felds). Bit işlemleri artık biraz (haha) basitleşiyor:
Biraz ayarlamak veya silmek için:
mybits.b = 1;
mybits.c = 0;
Biraz değiştirmek için:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
Biraz kontrol ediliyor:
if (mybits.c) //if mybits.c is non zero the next line below will execute
Bu yalnızca sabit boyutlu bit alanlarıyla çalışır. Aksi takdirde, önceki yazılarda açıklanan bit döndürme tekniklerine başvurmanız gerekir.
Bit kümesi işlemek ve temizlemek için bir başlık dosyasında tanımlanan makroları kullanın:
/* 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))
BITMASK_CHECK(x,y) ((x) & (y))
olmalıdır ((x) & (y)) == (y)
, aksi takdirde bitli maskesini yanlış sonuç verir (örn. 5
vs 3
/ * Merhaba tüm mezar kazıcılar için:) * /)
1
(uintmax_t)1
herhangi birinin bu makroları bir long
veya daha büyük bir türde kullanmaya çalışması durumunda olması veya benzer olması gerekir
BITMASK_CHECK_ALL(x,y)
olarak uygulanabilir!~((~(y))|(x))
!(~(x) & (y))
Bir kullanarak bazen değer enum
için isim bitleri:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
Sonra adları daha sonra kullanın . Yani yaz
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
ayarlamak, temizlemek ve test etmek. Bu şekilde sihirli sayıları kodunuzun geri kalanından gizlersiniz.
Bunun dışında Jeremy'nin çözümünü onaylıyorum.
clearbits()
yerine bir işlev yapabilirsiniz &= ~
. Bunun için neden bir numaralandırma kullanıyorsunuz? Bunların gizli rasgele değeri olan bir dizi benzersiz değişken oluşturmak için olduğunu düşündüm, ancak her birine belirli bir değer atarsınız. Peki onları değişken olarak tanımlamanın yararı nedir?
enum
İlgili sabitler için s kullanımı c programlamasında uzun bir yol kat eder. Modern derleyicilerle tek avantajı const short
ya da her ne olursa olsun açıkça birlikte gruplandırıldığından şüpheleniyorum . Ve onları bitmaskinden başka bir şey için istediğinizde otomatik numaralandırmayı elde edersiniz. Elbette c ++ 'da, size biraz ekstra statik hata kontrolü sağlayan farklı türler de oluştururlar.
enum ThingFlags
değeri nedir ThingError|ThingFlag1
?
int
. Bu, örtülü tamsayı yükseltmesi veya imzalı türlerde bitsel işlemler nedeniyle her türlü ince hataya neden olabilir. thingstate = ThingFlag1 >> 1
örneğin, uygulama tanımlı davranışı başlatır. thingstate = (ThingFlag1 >> x) << y
tanımlanmamış davranışı tetikleyebilir. Ve bunun gibi. Güvende olmak için her zaman imzasız bir türe atın.
enum My16Bits: unsigned short { ... };
/*
** 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)))
Tamam, bir şeyleri analiz edelim ...
Bunların hepsinde sorun yaşadığınız genel ifade "(1L << (posn))" dir. Tüm bunlar, tek bitli bir maske oluşturmak ve herhangi bir tamsayı türüyle çalışacak. "Posn" bağımsız değişkeni biti istediğiniz konumu belirtir. Posn == 0 ise, bu ifade şu şekilde değerlendirilir:
0000 0000 0000 0000 0000 0000 0000 0001 binary.
Posn == 8 ise, şunları değerlendirir:
0000 0000 0000 0000 0000 0001 0000 0000 binary.
Başka bir deyişle, belirtilen konumda 1 olan 0'lık bir alan oluşturur. Tek zor kısım BitClr () makrosundadır, burada 1'lerin alanına tek bir 0 bit ayarlamamız gerekir. Bu, tilde (~) operatörü tarafından belirtilenle aynı ifadenin 1'in tamamlayıcısı kullanılarak gerçekleştirilir.
Maske oluşturulduktan sonra, tam da önerdiğiniz gibi, bitsel ve (&) veya (|) ve xor (^) operatörlerini kullanarak argümana uygulanır. Maske uzun tipte olduğundan, makrolar char, short, int veya long'larda da çalışır.
Sonuç olarak, bunun tüm problem sınıflarına genel bir çözüm olmasıdır. Tabii ki, bu makrolardan herhangi birinin eşdeğerini, her ihtiyacınız olduğunda açık maske değerleriyle yeniden yazmak mümkündür ve neden gereklidir? Unutmayın, makro ikamesi ön işlemcide gerçekleşir ve bu nedenle üretilen kod, değerlerin derleyici tarafından sabit olarak kabul edildiğini yansıtacaktır - yani, her ihtiyacınız olduğunda "tekerleği yeniden icat etmek" için genelleştirilmiş makroları kullanmak kadar etkilidir biraz manipülasyon yapmak.
İkna? İşte bazı test kodu - Watcom C'yi tam optimizasyonla ve _cdecl kullanmadan kullandım, böylece ortaya çıkan sökme mümkün olduğunca temiz olacak:
---- [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 (demonte)] -------------------------------------- ---------
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] ------------------------------------------- ----------------------
arg
ise long long
. 1L
mümkün olan en geniş tür olması gerekir (uintmax_t)1
. ( 1ull
Bitsel işleçleri kullanın: &
|
Son biti ayarlamak için 000b
:
foo = foo | 001b
Son biti kontrol etmek için foo
:
if ( foo & 001b ) ....
İçindeki son biti temizlemek için foo
:
foo = foo & 110b
XXXb
Açıklık için kullandım . Bitleri paketlediğiniz veri yapısına bağlı olarak muhtemelen HEX temsili ile çalışacaksınız.
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
Yeni başlayanlar için bir örnekle biraz daha açıklamak istiyorum:
Misal:
value is 0x55;
bitnum : 3rd.
&
Operatör denetim ikili kullanılır:
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)
Değiştir veya Çevir:
0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)
|
operatör: biti ayarla
0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
İşte en çok işaretsiz tamsayı dizisi unsigned char
için size_t
(bu ile çalışmak için verimli olması gereken en büyük tip) için çalışan en sevdiğim bit aritmetik makro :
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))
Biraz ayarlamak için:
BITOP(array, bit, |=);
Biraz temizlemek için:
BITOP(array, bit, &=~);
Biraz değiştirmek için:
BITOP(array, bit, ^=);
Biraz test etmek için:
if (BITOP(array, bit, &)) ...
vb.
BITOP(array, bit++, |=);
Bir döngüde kullanmak büyük olasılıkla arayanın istediği şeyi yapmaz.
BITCELL(a,b) |= BITMASK(a,b);
(hem take a
bağımsız değişken olarak boyutunu belirlemek için, ama ikincisi değerlendirmek asla a
beri yalnızca içinde görünür sizeof
).
(size_t)
kadro sadece imzasız matematik ile sigortalanmış gibi görünüyor %
. Acaba (unsigned)
orada.
(size_t)(b)/(8*sizeof *(a))
Gereksiz daralabilir b
bölünmeden önce. Sadece çok büyük bit dizileriyle ilgili bir sorun. Hala ilginç bir makro.
Bu "gömülü" olarak etiketlendiğinden, bir mikro denetleyici kullandığınızı varsayacağım. Yukarıdaki önerilerin tümü geçerlidir ve çalışır (okuma-değiştirme-yazma, sendikalar, yapılar vb.).
Bununla birlikte, osiloskop tabanlı bir hata ayıklama sırasında, bu yöntemlerin CPU döngülerinde doğrudan mikroun PORTnSET / PORTnCLEAR kayıtlarına bir değer yazmaya kıyasla önemli bir yükü olduğunu fark ettim. frekansı ISR'nin geçiş pimleri.
Tanıdık olmayanlar için: Benim örneğimde, mikro çıkış pinlerini yansıtan genel bir pin-durumu kaydı PORTn'a sahiptir, bu nedenle PORTn | = BIT_TO_SET yapmak bu yazmacıya bir okuma-değiştirme-yazma ile sonuçlanır. Ancak, PORTnSET / PORTnCLEAR kayıtlarında "lütfen bu bit 1'i yap" (SET) veya "lütfen bu biti sıfır yap" (TEMİZLE) ve "0", "pimi yalnız bırak" anlamına gelir. bu nedenle, biti ayarlamanıza veya temizlemenize (her zaman uygun değil), ancak çok daha hızlı bir reaksiyona ve daha küçük birleştirilmiş koda bağlı olarak iki bağlantı noktası adresiyle sonuçlanırsınız .
volatile
ve bu nedenle derleyicinin bu kayıtları içeren kod üzerinde herhangi bir optimizasyon yapamayacağını unutmayın. Bu nedenle, bu kodu sökmek ve montajcı seviyesinde nasıl ortaya çıktığını görmek iyi bir uygulamadır.
Bitfield yaklaşımının gömülü arenada başka avantajları vardır. Belirli bir donanım kaydındaki bitlerle doğrudan eşleşen bir yapı tanımlayabilirsiniz.
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;
Biraz paketleme siparişinin farkında olmalısınız - ilk önce MSB olduğunu düşünüyorum, ancak bu uygulamaya bağlı olabilir. Ayrıca, derleyicinizin alan geçiş bayt sınırlarını nasıl işlediğini de doğrulayın.
Daha sonra tek tek değerleri önceki gibi okuyabilir, yazabilir ve test edebilirsiniz.
#define bit_test(x, y) ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
Örnek kullanım:
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;
}
Notlar: Bu, hızlı (esnekliği göz önüne alındığında) ve şubesiz olacak şekilde tasarlanmıştır. Sun Studio 8 derlendiğinde verimli SPARC makine kodu ile sonuçlanır; Ayrıca amd64 üzerinde MSVC ++ 2008 kullanarak test ettik. Bitleri ayarlamak ve temizlemek için benzer makrolar yapmak mümkündür. Bu çözümün diğer pek çok ile karşılaştırılmasındaki temel farkı, hemen hemen her tür değişkente herhangi bir konum için çalışmasıdır.
Daha genel, rastgele boyutlu bitmap'ler için:
#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)))
CHAR_BIT
tarafından zaten tanımlanmışsa limits.h
, kendi BITS
kodunuzu girmenize gerek yoktur (ve aslında kodunuzu daha da kötüleştirirsiniz)
Bu program herhangi bir veri bitini 0'dan 1'e veya 1'den 0'a değiştirmektir:
{
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);
}
}
}
Çok fazla twiddling yapıyorsanız, her şeyi daha hızlı hale getirecek maskeler kullanmak isteyebilirsiniz. Aşağıdaki işlevler çok hızlıdır ve hala esnektir (her boyuttaki bit haritalarında bit döndürülmesine izin verir).
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;
}
Not, bit 'n' yi 16 bit tamsayı olarak ayarlamak için aşağıdakileri yaparsınız:
TSetBit( n, &my_int);
Bit numarasının geçtiğiniz bit eşlemi aralığında olmasını sağlamak size bağlıdır. Baytlar, kelimeler, dwords, qwords, vb. üzerine ...).
Bunu kullan:
int ToggleNthBit ( unsigned char n, int num )
{
if(num & (1 << n))
num &= ~(1 << n);
else
num |= (1 << n);
return num;
}
bitset
Cevabı genişletmek :
#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;
}
Tüm bu işlemleri Linux çekirdeğinde C programlama ile gerçekleştirmek istiyorsanız, Linux çekirdeğinin standart API'lerini kullanmanızı öneririm.
Bkz. 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
Not: Burada tüm işlem tek bir adımda gerçekleşir. Bu nedenle, tüm bunların SMP bilgisayarlarda bile atomik olması garanti edilir ve işlemciler arasında tutarlılığı korumak için kullanışlıdır.
Visual C 2010 ve belki de diğer birçok derleyici yerleşik boolean işlemleri için doğrudan desteğe sahiptir. Biraz boole gibi iki olası değere sahiptir, bu yüzden booleanları kullanabiliriz - tek bir bitten daha fazla yer kaplasalar bile bu gösterimde bellek. Bu, sizeof()
operatör bile düzgün çalışıyor.
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);
}
Yani, sorunuza IsGph[i] =1
, veyaIsGph[i] =0
da ayar ve temizleme bools kolay hale getirmek.
Yazdırılamayan karakterleri bulmak için:
// 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;
}
}
Bu kod hakkında "özel" bir şey olmadığını unutmayın. Biraz bir tamsayı gibi davranır - teknik olarak öyle. Yalnızca 2 ve 2 değeri alabilen 1 bitlik bir tam sayı.
Bir keresinde bu yaklaşımı, kredi_sayısının ISAM anahtarı olduğu yinelenen kredi kayıtlarını bulmak için, 6 haneli kredi numarasını bit dizisine bir dizin olarak kullanarak kullandım. Savagely hızlı ve 8 ay sonra, verileri almakta olduğumuz ana bilgisayar sisteminin aslında hatalı olduğunu kanıtladı. Bit dizilerinin sadeliği, doğruluklarına olan güveni çok yüksek kılar - örneğin bir arama yaklaşımı.
bool
. Hatta int
uygulamak için kullanılan C89 kurulumları için 4 bayt bilebool
İşte kullandığım bazı makrolar:
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)
Kullanılan değişken
int value, pos;
value - Veri
konumu - ayarlamak, silmek veya değiştirmek istediğiniz bitin konumu.
Biraz ayarla:
value = value | 1 << pos;
Biraz temizle:
value = value & ~(1 << pos);
Biraz değiştir:
value = value ^ 1 << pos;
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);
}
check_nth_bit
olabilir bool
.
Diyelim ki ilk önce birkaç şeyin
num = 55
tamsayı işlemleri yapmasını sağlayın (set, get, clear, toggle).
n = 4
Bitsel işlemleri gerçekleştirmek için 0 tabanlı bit konumu.
nth
num sağ vardiya bit num
, n
zaman. Ardından bitlerle VE &
1 ile gerçekleştirin .bit = (num >> n) & 1;
Nasıl çalışır?
0011 0111 (55 in decimal)
>> 4 (right shift 4 times)
-----------------
0000 0011
& 0000 0001 (1 in decimal)
-----------------
=> 0000 0001 (final result)
n
kez. Ardından ile bitsel VEYA |
işlemi gerçekleştirin num
.num |= (1 << n); // Equivalent to; num = (1 << n) | num;
Nasıl çalışır?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
| 0011 0111 (55 in decimal)
-----------------
=> 0001 0000 (final result)
n
çarpı yani 1 << n
.~ (1 << n)
.&
yukarıdaki sonuç ve ile bitsel VE işlemi gerçekleştirin num
. Yukarıdaki üç adım birlikte şöyle yazılabilir num & (~ (1 << n))
;num &= (~(1 << n)); // Equivalent to; num = num & (~(1 << n));
Nasıl çalışır?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
~ 0001 0000
-----------------
1110 1111
& 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
Biraz geçiş yapmak için bitsel XOR ^
operatörünü kullanırız. Her iki işlenenin karşılık gelen biti farklıysa, Bitwise XOR operatörü 1 olarak değerlendirilir, aksi takdirde 0 olarak değerlendirilir.
Bu, biraz geçiş yapmak anlamına gelir, geçiş yapmak istediğiniz bit ve 1 ile XOR işlemini gerçekleştirmemiz gerekir.
num ^= (1 << n); // Equivalent to; num = num ^ (1 << n);
Nasıl çalışır?
0 ^ 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)
Önerilen okuma - Bitsel operatör alıştırmaları
Tek bir biti nasıl ayarlar, temizler ve değiştirirsiniz?
Maskeyi oluşturmaya çalışırken yaygın bir kodlama tuzağını ele almak için:
1
her zaman yeterince geniş değil
Daha number
geniş bir tip olduğunda ne gibi problemler olur 1
? tanımlanmamış davranışa (UB) yol açan
x
değişiklik için çok büyük olabilir . Çok büyük olmasa bile , yeterince önemli bitleri çevirmeyebilir.1 << x
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'in yeterince geniş olmasını sağlamak için:
Kod kullanabilir 1ull
veya bilgili bir şekilde kullanabilir (uintmax_t)1
ve derleyicinin optimize etmesine izin verebilir .
number |= (1ull << x);
number |= ((uintmax_t)1 << x);
Ya da yayın - kodun doğru ve güncel kalmasını sağlayan kodlama / inceleme / bakım sorunlarını yapar.
number |= (type_of_number)1 << x;
Ya 1
da en az onun kadar geniş bir matematik işlemini zorlayarak teşvik edin number
.
number |= (number*0 + 1) << x;
Çoğu bit manipülasyonunda olduğu gibi, imzalı olanlarla değil , imzalanmamış türlerle çalışmak en iyisidir
number |= (type_of_number)1 << x;
ne number |= (number*0 + 1) << x;
uygun ne de ... Aslında, öyle de değil number |= (1ull << x);
. Pozisyona göre yapmanın taşınabilir bir yolu var mı?
C ++ 11 şablonlu sürüm (başlığa konur):
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;}
}
;
işlev tanımlarından sonra neden var ?)
(variable & bits == bits)
?
((variable & bits) == bits)
std::bitset
c ++ 11'de kullanın
Bu program @ Jeremy'nin yukarıdaki çözümüne dayanmaktadır. Birisi çabucak oynamak isterse.
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
N bit'i değiştirmek için C dilinde şu işlevlerden birini deneyin:
char bitfield;
// Start at 0th position
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}
Veya
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}
Veya
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;
}
value << n
tanımlanmamış davranışa neden olabilir