Qanday qilib biroz o'rnatasiz, tozalaysiz va o'zgartirasiz?
Bitta bitni qanday sozlash, tozalash va almashtirish mumkin?
Javoblar (27)
Bir oz sozlash
Bitni o'rnatish uchun bit yo'nalishi bo'yicha OR (|
) operatoridan foydalaning.
number |= 1UL << n;
Bu number
ning n
-bitini o'rnatadi. n
nolga teng bo'lishi kerak, agar siz 1
-bitni va shunga o'xshashni n-1
gacha o'rnatmoqchi bo'lsangiz, n
-bitni o'rnatmoqchi bo'lsangiz.
number
unsigned long
dan kengroq bo'lsa, 1ULL
dan foydalaning; 1UL << n
ning ko'tarilishi 1UL << n
ni baholashdan keyin sodir bo'ladi, bunda long
kengligidan kattaroqqa siljish noaniq bo'ladi. Xuddi shu narsa qolgan barcha misollar uchun ham amal qiladi.
Bir oz tozalash
Bir oz tozalash uchun bit bo'yicha AND operatoridan (&
) foydalaning.
number &= ~(1UL << n);
Bu number
ning n
-bitini tozalaydi. Bit satrni bitli NOT operatori (~
) bilan teskari o'zgartirishingiz kerak, keyin esa AND.
Bir oz almashtirish
XOR operatoridan (^
) biroz almashtirish uchun foydalanish mumkin.
number ^= 1UL << n;
Bu number
ning n
-bitini almashtiradi.
Biroz tekshirilmoqda
Siz buni so'ramagan edingiz, lekin men uni qo'shishim mumkin.
Bir oz tekshirish uchun n raqamini o'ngga, so'ngra bit bo'yicha VA uni:
bit = (number >> n) & 1U;
Bu number
ning n
-bitining qiymatini bit
o'zgaruvchisiga qo'yadi.
n-bitni x ga o'zgartirish
n
th bitni 1
yoki 0
ga o'rnatishga 2 ni to'ldiruvchi C++ ilovasida quyidagilar orqali erishish mumkin:
number ^= (-x ^ number) & (1UL << n);
Agar x
1
bo'lsa, n
biti o'rnatiladi va x
0
bo'lsa, o'chiriladi. Agar x
boshqa qiymatga ega bo'lsa, siz axlat olasiz. x = !!x
uni 0 yoki 1 ga mantiqiylashtiradi.
Buni 2 ning to'ldiruvchini inkor qilish harakatidan mustaqil qilish uchun (bu erda -1
ning barcha bitlari o'rnatilgan, 1 ning to'ldiruvchisi yoki belgisi/kattaligi C++ ilovasidan farqli o'laroq), imzosiz inkordan foydalaning.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
or
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
Odatda portativ bitni manipulyatsiya qilish uchun imzosiz turlardan foydalanish yaxshi fikr.
or
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
n
-bitni tozalaydi va (x << n)
n
-bitni x
ga o'rnatadi.
Umuman olganda, kodni nusxalash/joylashtirmaslik ham yaxshi fikr, shuning uchun ko'p odamlar preprotsessor makroslaridan foydalanadilar (masalan, hamjamiyat wiki javobi quyida.) yoki qandaydir inkapsulyatsiya.
number
int
dan kengroq bo'lsa, bu erda bit-fiddling jimgina bajarilmaydi.
- person anatolyg; 09.05.2013
bit = (number >> x) & 1
ga almashtirmaysiz
- person aaronman; 26.06.2013
1
- int
harfi, imzolangan. Shunday qilib, bu erda barcha operatsiyalar imzolangan raqamlarda ishlaydi, bu standartlar bilan yaxshi belgilanmagan. Standartlar ikkita to'ldiruvchini yoki arifmetik siljishni kafolatlamaydi, shuning uchun 1U
dan foydalanish yaxshidir.
- person Siyuan Ren; 10.12.2013
unsigned long long
gacha bo'lgan barcha o'zgaruvchilar uchun... __int128
kabi amalda aniqlangan kengaytmalar bo'lishi mumkin. Juda xavfsiz bo'lish uchun (uintmax_t)1 << x
- person M.M; 07.02.2015
number = number & ~(1 << n) | (x << n);
ni afzal ko'raman.
- person jiasli; 24.03.2015
number
int
dan katta bo'lsa va n
int
dagi bitlar sonidan katta yoki teng bo'lsa, bu bayonot muvaffaqiyatsiz bo'ladi. Bu holatda hatto aniqlanmagan xatti-harakatlarni ham chaqiradi. number = number & ~((uintmax_t)1 << n) | ((uintmax_t)x << n);
umumiy ifoda boʻlib, u number
ning barcha oʻlchamlari uchun ishlashi kerak, lekin kichikroq oʻlchamlar uchun yomon va samarasiz kod yaratishi mumkin.
- person chqrlie; 24.03.2015
-x
kabi operatsiyalardan foydalanish xavfsiz emas, chunki C standarti imzolangan butun sonlarni (masalan,) belgi-kattalik, birlarni to'ldiruvchi yoki kerakli diapazonni ifodalay oladigan boshqa tizim bo'lishiga imkon beradi, ya'ni -x
emas (~x) + 1
bilan bir xil bo'lishi kerak. Bu zamonaviy arxitekturada unchalik katta ish emas, lekin siz yetarlicha aqlli optimallashtiruvchi kompilyator sizning kodingiz bilan nima qilishini hech qachon bilmaysiz.
- person Kevin; 18.01.2016
!
o'rniga ~
dan foydalanamiz?
- person 71GA; 30.01.2017
~
) barcha bitlarni o'zgartiradi, shuning uchun ~0xFFF0FFFF
0x000F0000
bo'ladi. Mantiqiy emas (!
) qiymat nolga teng bo'lsa 0 ni yoki qiymat nolga teng bo'lsa 1 ni beradi, shuning uchun !0xFFF0FFFF
0x00000000
bo'ladi.
- person Adrian McCarthy; 05.09.2017
-1
0b1111..1110
bo‘ladi. (Hammasi -0
). C++ shuningdek, belgi/kattalik butun sonlarini ko'rsatishga imkon beradi, bunda -x
shunchaki belgi bitini aylantiradi. Men buni ta'kidlash uchun bu javobni yangiladim. Agar siz faqat 2 ning to'ldiruvchi C++ ilovalarini maqsad qilgan bo'lsangiz, bu juda yaxshi. Bu UB emas, u faqat amalga oshirish bilan belgilanadi, shuning uchun 2 ning to'ldiruvchisi sifatida belgilangan imzolangan butun sonlarni amalga oshirishda to'g'ri ishlash talab qilinadi. Bundan tashqari, 1ULL
talab qilinishi mumkinligini eslatib, doimiylarni 1UL
ga o'zgartirdim.
- person Peter Cordes; 10.11.2017
-x
UB, agar x INT_MIN bo'lsa.
- person Kevin; 10.11.2017
-(unsigned long)x
bo'lishi kerak, bu ham imzolangan tamsayı ko'rinishini chetlab o'tadi. (imzosiz asos 2 2 ning toʻldiruvchi semantikasiga mos keladi.) Lekin u faqat x
0 yoki 1 boʻlsa toʻgʻri ishlaydi. Esda tutingki, biz n
bitini x
ga oʻrnatyapmiz.
- person Peter Cordes; 11.11.2017
0U - 1U
-› all-ones uchun baribir unsigned dan foydalanmoqchisiz. Endi u qanday ko'rinadi? Javobni oddiy saqlashga harakat qildim. !!x
bilan mantiqiylashtirish kerak bo'lishi mumkinligini aytdim. Agar bu mening javobim bo'lsa, men har doim imzosiz foydalanish haqida ko'proq matn kiritishim mumkin edi, lekin men bu eski kanonik javobni saqlab qolaman. (Jeremi, o'zgarishlar sizga yoqadi deb umid qilaman, o'zgartirishlarimni o'z so'zlaringiz bilan yoki 9 yildan keyin aytmoqchi bo'lgan boshqa narsalarni kiritish uchun tahrirlashni xohlashingiz mumkin.)
- person Peter Cordes; 11.11.2017
n
-bit x
boʻlimiga boshqa uchinchi tomon tahriri tomonidan qoʻshilganini va birinchi navbatda Jeremining ishi emasligini payqadim.
- person Peter Cordes; 11.11.2017
set bit to value
operatsiyasini bajarish uchun bitta iborani o'ylab topishim kerak degan fikrda bo'lganman. Odatda men apparatda save state
+ unconditionally set/clear
+ restore state
ni bajaraman. Qanday bo'lmasin, men tasodifan bunga qoqilib qoldim va yuqoridagi ifodani albatta o'g'irlayman.
- person sherrellbc; 15.01.2021
number = (number | (1UL << n)) ^ (!x << n)
Mantiqiy bo'lmagan va bir oz yo'qni olib tashlash uchun soddalashtirilgan
- person Shogan Aversa-Druesne; 18.01.2021
x
ga o'zgartirganda samaraliroq bo'ladimi, deb o'ylayman. number = (number & ~(1UL << n)) | (x << n);
ikkita bitli siljishni, bitta baytni aylantirish, bitta VA, bitta OR va nihoyat bitta topshiriqni yaratmaydi. if (x) { number |= (1 << n); } else { number &= ~(1 << n); }
bitta taqqoslashni, bir bitni siljitishni, yoki YOKI yoki VA ni baytni aylantirish bilan, shuningdek, topshiriqni hosil qiladi. Eng yomon holatda 6 va 5 ta operatsiya (bitni tozalash). Bitni o'rnatishda 6 va 4. Ko'proq o'qilishi mumkin. Lekin, ehtimol, ba'zi operatsiyalar qimmatroqdir?
- person Smartskaft2; 02.05.2021
x
o'rtasida tezlikni oshirish farqi bor, ammo x qiymatini tasodifiylashtirishda if
bo'lmagan yechim if
-yechimdan ikki baravar tezroq bo'ladi: godbolt.org/z/5aEbKchzf Demak, ha, siz haqsiz, filialni bashorat qilish samaradorlikni pasaytiradi.
- person JulianH; 28.05.2021
Standart C++ kutubxonasidan foydalanish: std::bitset<N>
.
Yoki Boost versiyasi: boost::dynamic_bitset
.
O'zingizni siljitishning hojati yo'q:
#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 versiyasi kompilyatsiya vaqti oʻlchamidagi standart kutubxona bilan solishtirganda ish vaqti oʻlchamidagi bitlar toʻplamiga ruxsat beradi. bitset.
sudo apt-get install boost-devel
- person Martin York; 13.08.2014
std::bitset
haqida aniq gapiramiz.
- person Martin York; 22.01.2020
Boshqa variant - bit maydonlaridan foydalanish:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
3-bitli maydonni belgilaydi (aslida, bu uchta 1-bitli dala). Bit operatsiyalari endi biroz (haha) soddalashdi:
Bir oz o'rnatish yoki tozalash uchun:
mybits.b = 1;
mybits.c = 0;
Bir oz o'zgartirish uchun:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
Biroz tekshirish:
if (mybits.c) //if mybits.c is non zero the next line below will execute
Bu faqat qattiq o'lchamli bit maydonlari bilan ishlaydi. Aks holda, oldingi postlarda tasvirlangan bit-twiddling usullariga murojaat qilishingiz kerak.
sizeof(mybits)
ni tekshirgandan so'ng, men 12 (ya'ni, uchta ints
o'lchami) olaman. Bu xotirada ajratilgan joymi yoki sizeof
funksiyasidagi xatomi?
- person iGbanam; 29.11.2012
gcc
4.4.5 versiyasidan foydalanmoqdaman
- person iGbanam; 29.11.2012
struct
ni butun son bilan (odatda anonim) union
ichiga qo'yish mumkin va hokazo. U ishlaydi. (Men bu eski mavzu btw ekanligini tushunaman)
- person Shade; 17.05.2014
__attribute__((packed))
ni xohlashingiz mumkin
- person ; 28.06.2020
Bit to'plamini boshqarish va tozalash uchun sarlavha faylida belgilangan makroslardan foydalanaman:
/* 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)))
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))
BITMASK_CHECK(x,y) ((x) & (y))
((x) & (y)) == (y)
bo'lishi kerak, aks holda u multibitli niqobda noto'g'ri natija beradi (masalan, 5
va 3
) /*Barcha qabr qazuvchilarga salom :)*/
- person brigadir; 11.12.2014
1
(uintmax_t)1
yoki shunga o'xshash bo'lishi kerak, agar kimdir bu makroslardan long
yoki undan kattaroq turdagi foydalanmoqchi bo'lsa
- person M.M; 07.02.2015
1ULL
ko'pgina ilovalarda (uintmax_t)
kabi ishlaydi.
- person Peter Cordes; 11.11.2017
BITMASK_CHECK_ALL(x,y)
!~((~(y))|(x))
sifatida amalga oshirilishi mumkin
- person Handy999; 20.11.2018
!(~(x) & (y))
ni olish uchun qayta tartibga solishdan keyin nima uchun bu ishlayotganini tushunish biroz osonroq.
- person Tavian Barnes; 13.08.2019
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1
- person William Martens; 16.02.2021
Ba'zan bitlarni ismlash uchun enum
dan foydalanishga arziydi:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
Keyin ismlar dan keyinroq foydalaning. ya'ni yozish
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
o'rnatish, tozalash va sinab ko'rish. Shunday qilib, siz sehrli raqamlarni kodingizning qolgan qismidan yashirasiz.
Bundan tashqari, men Jeremining yechimini ma'qullayman.
&= ~
o'rniga clearbits()
funksiyasini yaratishingiz mumkin. Nega buning uchun enum dan foydalanasiz? Men bular yashirin o'zboshimchalik qiymatiga ega bo'lgan noyob o'zgaruvchilar to'plamini yaratish uchun deb o'yladim, lekin siz har biriga aniq qiymat berasiz. Xo'sh, ularni o'zgaruvchi sifatida belgilashdan qanday foyda bor?
- person endolith; 20.12.2011
enum
s dan foydalanish c dasturlashda uzoq vaqtga borib taqaladi. Men zamonaviy kompilyatorlarning const short
ga nisbatan yagona afzalligi yoki ular aniq guruhlanganligidan shubhalanaman. Va agar siz ularni bitmasklardan boshqaga olishni istasangiz, siz avtomatik raqamlashni olasiz. Albatta, c ++ da ular alohida turlarni hosil qiladi, bu sizga statik xatolarni tekshirish uchun ozgina qo'shimcha imkoniyatlar beradi.
- person dmckee --- ex-moderator kitten; 22.12.2011
ThingError|ThingFlag1
uchun enum ThingFlags
qiymati qanday?
- person Luis Colorado; 30.09.2014
int
turdagi imzolanganligini yodda tuting. Bu yashirin butun sonlarni ko'tarish yoki imzolangan turlarda bitli operatsiyalar tufayli har qanday nozik xatolarga olib kelishi mumkin. thingstate = ThingFlag1 >> 1
, masalan, amalga oshirishda aniqlangan xatti-harakatni chaqiradi. thingstate = (ThingFlag1 >> x) << y
aniqlanmagan xatti-harakatni chaqirishi mumkin. Va hokazo. Xavfsiz bo'lish uchun har doim imzosiz turga o'tkazing.
- person Lundin; 14.12.2015
enum My16Bits: unsigned short { ... };
- person Aiken Drum; 15.03.2016
snip-c.zip bitops.h dan:
/*
** 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)))
OK, keling, narsalarni tahlil qilaylik ...
Bularning barchasida muammoga duch kelayotganingiz ko'rinadigan umumiy ifoda "(1L ‹‹ (posn))". Bularning barchasi bitta bitli va har qanday butun son turi bilan ishlaydigan niqob yaratishdir. "Posn" argumenti bitni xohlagan joyni belgilaydi. Agar posn==0 bo'lsa, bu ifoda quyidagicha baholanadi:
0000 0000 0000 0000 0000 0000 0000 0001 binary.
Agar posn==8 bo'lsa, u quyidagicha baholanadi:
0000 0000 0000 0000 0000 0001 0000 0000 binary.
Boshqacha qilib aytadigan bo'lsak, u ko'rsatilgan pozitsiyada 1 bilan 0 maydonini yaratadi. BitClr() makrosidagi yagona qiyin qism, bu erda biz 1 lar maydoniga bitta 0 bitni o'rnatishimiz kerak. Bu tilde (~) operatori bilan belgilangan iboraning 1 ning to‘ldiruvchisi yordamida amalga oshiriladi.
Niqob yaratilgandan so'ng, u siz taklif qilganingizdek, bit va (&), yoki (|) va xor (^) operatorlari yordamida argumentga qo'llaniladi. Niqob uzun turdagi bo'lgani uchun, makroslar char, short, int yoki long larda ham ishlaydi.
Xulosa shuki, bu butun muammolar sinfining umumiy yechimidir. Albatta, har safar kerak bo'lganda ushbu makroslarning har qandayining ekvivalentini aniq niqob qiymatlari bilan qayta yozish mumkin va hatto maqsadga muvofiqdir, lekin nima uchun buni qilish kerak? Esda tutingki, makro almashtirish preprotsessorda sodir bo'ladi va shuning uchun hosil qilingan kod qiymatlar kompilyator tomonidan doimiy deb hisoblanishi haqiqatini aks ettiradi - ya'ni har safar "g'ildirakni qayta ixtiro qilish" uchun umumiy makrolardan foydalanish samaralidir. bit manipulyatsiyasi qiling.
Ishonchsizmi? Mana bir nechta test kodi - men Watcom C-ni to'liq optimallashtirish bilan va _cdecl-dan foydalanmasdan ishlatganman, natijada demontaj imkon qadar toza bo'ladi:
----[ 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 (demontaj qilingan)]-------------------------------------- ---------
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
long long
bo'lsa, bu bajarilmaydi. 1L
mumkin bo'lgan eng keng turdagi bo'lishi kerak, shuning uchun (uintmax_t)1
. (Siz 1ull
bilan qutulishingiz mumkin)
- person M.M; 07.02.2015
Yangi boshlanuvchilar uchun men misol bilan biroz ko'proq tushuntirmoqchiman:
Misol:
value is 0x55;
bitnum : 3rd.
Bitni tekshirish uchun &
operatori ishlatiladi:
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)
Oʻzgartirish yoki aylantirish:
0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)
|
operator: bitni o'rnating
0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
Bu "ko'milgan" deb belgilangani uchun siz mikrokontrollerdan foydalanyapsiz deb o'ylayman. Yuqoridagi barcha takliflar amal qiladi va ishlaydi (o'qish-o'zgartirish-yozish, uyushmalar, tuzilmalar va boshqalar).
Biroq, osiloskopga asoslangan disk raskadrovka bilan shug'ullanayotganda, bu usullar mikro-ning PORTnSET / PORTnCLEAR registrlariga to'g'ridan-to'g'ri qiymat yozish bilan solishtirganda, protsessor sikllarida sezilarli yukga ega ekanligini ko'rib hayratda qoldim, bu qattiq halqalar / yuqori bo'lgan joylarda haqiqiy farq qiladi. -chastotali ISR ning almashtirish pinlari.
Notanishlar uchun: Mening misolimda mikroda chiqish pinlarini aks ettiruvchi PORTn umumiy pin-holat registriga ega, shuning uchun PORTn |= BIT_TO_SET ni bajarish ushbu registrga o'qish-o'zgartirish-yozishni keltirib chiqaradi. Biroq, PORTnSET / PORTnCLEAR registrlari "iltimos, bu bitni 1 qiling" (SET) yoki "iltimos, bu bitni nolga aylantiring" (CLEAR) va "0" "pinni yolg'iz qoldiring" degan ma'noni bildirish uchun "1" ni oladi. Shunday qilib, siz bitni o'rnatishingiz yoki tozalashingizga qarab ikkita port manziliga ega bo'lasiz (har doim ham qulay emas), lekin juda tezroq reaktsiya va kichikroq yig'ilgan kod.
volatile
sifatida aniqlanadi va shuning uchun kompilyator bunday registrlar ishtirokidagi kodni optimallashtirishni amalga oshira olmaydi. Shuning uchun bunday kodni qismlarga ajratish va uning assembler darajasida qanday ekanligini ko'rish yaxshi amaliyotdir.
- person Lundin; 14.12.2015
Mana mening sevimli bit arifmetik makrosim, u unsigned char
dan size_t
gacha boʻlgan har qanday belgisiz butun massiv uchun ishlaydi (bu bilan ishlashda samarali boʻlishi kerak boʻlgan eng katta tur):
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))
Bir oz sozlash uchun:
BITOP(array, bit, |=);
Biroz tozalash uchun:
BITOP(array, bit, &=~);
Bir oz o'zgartirish uchun:
BITOP(array, bit, ^=);
Bir oz sinab ko'rish uchun:
if (BITOP(array, bit, &)) ...
va boshqalar.
BITOP(array, bit++, |=);
dan foydalanish, ehtimol, qo'ng'iroq qiluvchi xohlagan narsani bajarmaydi.
- person foraidt; 13.07.2010
BITCELL(a,b) |= BITMASK(a,b);
(ikkalasi ham o'lchamni aniqlash uchun argument sifatida a
ni oladi, lekin ikkinchisi hech qachon bo'lmaydi) a
ni baholang, chunki u faqat sizeof
da ko'rinadi).
- person R.. GitHub STOP HELPING ICE; 13.07.2010
(size_t)
tarkib faqat %
bilan imzosiz matematikani sug'urtalash uchun u erda bo'lganga o'xshaydi. U erda (unsigned)
bo'lishi mumkin.
- person chux - Reinstate Monica; 27.09.2017
(size_t)(b)/(8*sizeof *(a))
keraksiz ravishda bo'linishdan oldin b
ni toraytirishi mumkin. Faqat juda katta bit massivlari bilan bog'liq muammo. Hali ham qiziqarli makro.
- person chux - Reinstate Monica; 27.09.2017
Bitfield yondashuvi o'rnatilgan arenada boshqa afzalliklarga ega. Siz ma'lum bir apparat registridagi bitlarga to'g'ridan-to'g'ri mos keladigan tuzilmani belgilashingiz mumkin.
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;
Bitlarni qadoqlash tartibidan xabardor bo'lishingiz kerak - menimcha, bu birinchi navbatda MSB, lekin bu amalga oshirishga bog'liq bo'lishi mumkin. Shuningdek, kompilyatoringiz bayt chegaralarini kesib o'tgan maydonlarni qanday ishlov berishini tekshiring.
Keyin oldingi kabi individual qiymatlarni o'qishingiz, yozishingiz, sinab ko'rishingiz mumkin.
Ixtiyoriy turdagi o'zgaruvchida ixtiyoriy joyda bir oz tekshiring:
#define bit_test(x, y) ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
Namunali foydalanish:
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;
}
Eslatmalar: Bu tezkor (moslashuvchanligi hisobga olingan holda) va tarmoq boʻlmagan boʻlishi uchun moʻljallangan. Sun Studio 8 kompilyatsiya qilinganda samarali SPARC mashina kodiga olib keladi; Men uni amd64 da MSVC++ 2008 yordamida sinab ko'rdim. Bitlarni o'rnatish va tozalash uchun shunga o'xshash makroslarni yaratish mumkin. Ushbu yechimning boshqa ko'plab variantlardan asosiy farqi shundaki, u deyarli har qanday turdagi o'zgaruvchilarda har qanday joy uchun ishlaydi.
Umuman olganda, ixtiyoriy o'lchamdagi bitmaplar uchun:
#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
allaqachon limits.h
tomonidan belgilangan, siz o'zingizning BITS
ni qo'yishingiz shart emas (va aslida bu bilan kodingizni yomonlashtirasiz)
- person M.M; 07.02.2015
Ushbu dastur har qanday ma'lumot bitini 0 dan 1 ga yoki 1 dan 0 ga o'zgartirish uchun mo'ljallangan:
{
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);
}
}
}
Buni ishlating:
int ToggleNthBit ( unsigned char n, int num )
{
if(num & (1 << n))
num &= ~(1 << n);
else
num |= (1 << n);
return num;
}
Agar siz juda ko'p chayqalayotgan bo'lsangiz, hamma narsani tezlashtiradigan niqoblardan foydalanishni xohlashingiz mumkin. Quyidagi funktsiyalar juda tez va hali ham moslashuvchan (ular har qanday o'lchamdagi bit xaritalarida bitni aylantirishga imkon beradi).
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;
}
E'tibor bering, 16 bitli butun sonda "n" bitini o'rnatish uchun quyidagilarni bajaring:
TSetBit( n, &my_int);
Bit raqami siz o'tadigan bit xaritasi oralig'ida bo'lishini ta'minlash sizga bog'liq. E'tibor bering, baytlar, so'zlar, dwords, qwords va hokazolar xotirada bir-biriga to'g'ri mos keladigan kichik endian protsessorlari uchun (asosiy sabab, kichik endian protsessorlari katta endian protsessorlariga qaraganda "yaxshiroq". kuni...).
bitset
javobni kengaytirish:
#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;
}
Avval bir nechta narsani faraz qilaylik
num = 55
Bit bo'yicha operatsiyalarni bajarish uchun butun son (o'rnatish, olish, tozalash, almashtirish).n = 4
Bit bo'yicha operatsiyalarni bajarish uchun 0 asoslangan bit pozitsiyasi.
Qanday qilib bir oz olish mumkin?
- Raqamning
nth
bitini olish uchun o'ngga siljishnum
,n
marta. Keyin bit bo'yicha VA&
ni 1 bilan bajaring.
bit = (num >> n) & 1;
Bu qanday ishlaydi?
0011 0111 (55 in decimal)
>> 4 (right shift 4 times)
-----------------
0000 0011
& 0000 0001 (1 in decimal)
-----------------
=> 0000 0001 (final result)
Qanday qilib bir oz o'rnatish kerak?
- Raqamning ma'lum bir bitini o'rnatish uchun. Chapga siljish 1
n
marta. Keyinnum
bilan bit bo'yicha YOKI|
amalni bajaring.
num |= (1 << n); // Equivalent to; num = (1 << n) | num;
Bu qanday ishlaydi?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
| 0011 0111 (55 in decimal)
-----------------
=> 0001 0000 (final result)
Qanday qilib biroz tozalash kerak?
- Chapga siljish 1,
n
marta, ya'ni1 << n
. - Yuqoridagi natija bilan bit bo'yicha to'ldirishni bajaring. Shunday qilib, n-bit o'rnatilmagan bo'lib qoladi va qolgan bit o'rnatiladi, ya'ni
~ (1 << n)
. - Nihoyat, yuqoridagi natija va
num
bilan bit bo'yicha VA&
amalni bajaring. Yuqoridagi uchta bosqichni birgalikdanum & (~ (1 << n))
deb yozish mumkin;
num &= (~(1 << n)); // Equivalent to; num = num & (~(1 << n));
Bu qanday ishlaydi?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
~ 0001 0000
-----------------
1110 1111
& 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
Qanday qilib biroz o'zgartirish mumkin?
Bir oz almashtirish uchun biz bitli XOR ^
operatoridan foydalanamiz. Bit bo'yicha XOR operatori ikkala operandning mos biti boshqacha bo'lsa, 1 ni baholaydi, aks holda 0 ga baholaydi.
Bu biroz almashtirishni anglatadi, biz XOR operatsiyasini siz o'zgartirmoqchi bo'lgan bit va 1 bilan bajarishimiz kerak.
num ^= (1 << n); // Equivalent to; num = num ^ (1 << n);
Bu qanday ishlaydi?
- Agar o'tish uchun bit 0 bo'lsa,
0 ^ 1 => 1
. - Agar o'tish uchun bit 1 bo'lsa,
1 ^ 1 => 0
.
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
^ 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
Tavsiya etilgan o'qish - Bitwise operatori mashqlari
Visual C 2010 va boshqa ko'plab kompilyatorlar o'rnatilgan mantiqiy operatsiyalarni to'g'ridan-to'g'ri qo'llab-quvvatlaydi. Bitta xuddi mantiqiy kabi ikkita mumkin bo'lgan qiymatga ega, shuning uchun biz mantiqiy qiymatlardan foydalanishimiz mumkin - ular bir bitdan ko'proq joy egallasa ham. ushbu tasvirda xotira. Bu ishlaydi, hatto sizeof()
operatori ham to'g'ri ishlaydi.
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);
}
Shunday qilib, sizning savolingizga IsGph[i] =1
yoki IsGph[i] =0
boollarni sozlash va tozalashni osonlashtiring.
Bosib bo'lmaydigan belgilarni topish uchun:
// 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;
}
}
E'tibor bering, ushbu kodda "maxsus" narsa yo'q. U bir oz butun songa o'xshaydi - bu texnik jihatdan shunday. 2 ta qiymatni va faqat 2 ta qiymatni saqlashi mumkin bo'lgan 1 bitli butun son.
Bir vaqtlar men ushbu yondashuvdan ikki nusxadagi kredit yozuvlarini topish uchun foydalanganman, bu erda loan_number ISAM kaliti bo'lib, 6 xonali kredit raqamini bit qatoriga indeks sifatida ishlatgan. Vahshiyona tez va 8 oydan so'ng biz ma'lumotlarni olayotgan asosiy kadrlar tizimi aslida noto'g'ri ishlayotganini isbotladi. Bit massivlarining soddaligi ularning to'g'riligiga ishonchni juda yuqori qiladi - masalan, qidiruv yondashuviga nisbatan.
bool
uchun kamida butun bir bayt xotiradan foydalanadi. bool
ni amalga oshirish uchun int
dan foydalanadigan C89 sozlamalari uchun hatto 4 bayt ham bo'lishi mumkin.
- person M.M; 07.02.2015
Agar siz ushbu barcha amallarni Linux yadrosida C dasturlash bilan bajarishni istasangiz, men Linux yadrosining standart API-laridan foydalanishni tavsiya qilaman.
Qarang: 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
Eslatma: Bu erda butun operatsiya bir bosqichda amalga oshiriladi. Shunday qilib, bularning barchasi SMP kompyuterlarida hamatomikbo'lishi kafolatlanadi va protsessorlar o'rtasida uyg'unlikni saqlash uchun foydalidir.
Men foydalanadigan ba'zi 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)
Bitta bitni qanday sozlash, tozalash va almashtirish mumkin?
Niqob yaratishga urinayotganda keng tarqalgan kodlash xatosini hal qilish uchun:1
har doim ham yetarlicha keng emas
number
1
dan kengroq turdagi bo'lsa, qanday muammolar yuzaga keladi?x
1 << x
siljishi uchun juda katta bo'lishi mumkin, bu esa aniqlanmagan xatti-harakatga (UB) olib keladi. x
unchalik katta bo'lmasa ham, ~
yetarlicha eng muhim bitlarni aylantira olmasligi mumkin.
// 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
Sug'urtalash uchun 1 yetarli keng:
Kod 1ull
yoki pedantik tarzda (uintmax_t)1
dan foydalanishi va kompilyatorga optimallashtirish imkonini berishi mumkin.
number |= (1ull << x);
number |= ((uintmax_t)1 << x);
Yoki translatsiya - bu translatsiyani to'g'ri va dolzarb saqlash uchun kodlash/ko'rib chiqish/xizmat ko'rsatish muammolarini keltirib chiqaradi.
number |= (type_of_number)1 << x;
Yoki 1
ni eng kamida number
turiga teng bo'lgan matematik amalni majburlash orqali muloyimlik bilan targ'ib qiling.
number |= (number*0 + 1) << x;
Ko'pgina bit manipulyatsiyalarida bo'lgani kabi, imzolangan emas, balki imzosiz turlar bilan ishlash yaxshiroqdir.
number |= (type_of_number)1 << x;
, na number |= (number*0 + 1) << x;
imzolangan turdagi belgi bitini o'rnatish uchun mos emas... Aslini olganda, number |= (1ull << x);
ham mos emas. Buni pozitsiya bo'yicha qilishning ko'chma usuli bormi?
- person chqrlie; 28.09.2017
Ushbu dastur @Jeremyning yuqoridagi yechimiga asoslangan. Agar kimdir tezda o'ynashni xohlasa.
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
Bir nechta bitlarni o'zgartirishni qo'llab-quvvatlaydigan shablonli versiya (sarlavha fayliga qo'yilgan) (btw AVR mikrokontrolörlarida ishlaydi):
namespace bit {
template <typename T1, typename T2>
constexpr inline T1 bitmask(T2 bit)
{return (T1)1 << bit;}
template <typename T1, typename T3, typename ...T2>
constexpr inline T1 bitmask(T3 bit, T2 ...bits)
{return ((T1)1 << bit) | bitmask<T1>(bits...);}
/** Set these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void set (T1 &variable, T2 ...bits)
{variable |= bitmask<T1>(bits...);}
/** Set only these bits (others will be cleared) */
template <typename T1, typename ...T2>
constexpr inline void setOnly (T1 &variable, T2 ...bits)
{variable = bitmask<T1>(bits...);}
/** Clear these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void clear (T1 &variable, T2 ...bits)
{variable &= ~bitmask<T1>(bits...);}
/** Flip these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void flip (T1 &variable, T2 ...bits)
{variable ^= bitmask<T1>(bits...);}
/** Check if any of these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isAnySet(const T1 &variable, T2 ...bits)
{return variable & bitmask<T1>(bits...);}
/** Check if all these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) == bitmask<T1>(bits...));}
/** Check if all these bits are not set */
template <typename T1, typename ...T2>
constexpr inline bool isNotSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) != bitmask<T1>(bits...));}
}
Foydalanish misoli:
#include <iostream>
#include <bitset> // for console output of binary values
// and include the code above of course
using namespace std;
int main() {
uint8_t v = 0b1111'1100;
bit::set(v, 0);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,1);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1,2,3,4,5,6,7);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,7);
cout << bitset<8>(v) << endl;
}
BTW: Optimizator argumenti (masalan: -O3) kompilyatorga yuborilmasa, constexpr va inline ishlatilmaydi. Kodni https://godbolt.org/ orqali sinab ko'ring va ASM chiqishiga qarang.
;
bor?)
- person melpomene; 10.02.2018
((variable & bits) == bits)
bo'lishi kerak edi
- person Joakim L. Christiansen; 27.02.2018
std::bitset
in c++11 dan foydalaning
- person pqnet; 25.10.2019
-1 dan foydalanmasdan n-bitni x (bit qiymati) ga o'rnatish
Ba'zan -1 yoki shunga o'xshash nimaga olib kelishiga ishonchingiz komil bo'lmasa, -1 dan foydalanmasdan n-bitni o'rnatishingiz mumkin:
number = (((number | (1 << n)) ^ (1 << n))) | (x << n);
Izoh: ((number | (1 << n)
n-bitni 1 ga qo'yadi (bu erda |
bit bo'yicha OR ni bildiradi), keyin (...) ^ (1 << n)
bilan biz n-bitni 0 ga o'rnatamiz va nihoyat (...) | x << n)
bilan biz 0 bo'lgan n-bitni (bit qiymati) x
ga o'rnatamiz.
Bu golang
da ishlaydi.
(number & ~(1 << n)) | (!!x << n)
kabi qisqaroq (va ehtimol, kompilyator sizning yechimingizni optimallashtirmasa, samaraliroq) bo'lishi mumkin.
- person Will Eccles; 08.05.2021
Bit bo'yicha asosiy operatsiyalarni bajarish uchun C tilidagi tartib:
#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;
}
N bitni o'zgartirish uchun C tilida ushbu funktsiyalardan birini sinab ko'ring:
char bitfield;
// Start at 0th position
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}
Or
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}
Or
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
aniqlanmagan xatti-harakatlarga olib kelishi mumkin
- person M.M; 07.02.2015
1
ni 0x1
yoki 1UL
ga o'zgartiring
- person KPCT; 18.04.2021
check_nth_bit
bool
bo'lishi mumkin.
- person Xeverous; 05.05.2020