Hoe stel, wis en schakel je een beetje in?
Antwoord 1, autoriteit 100%
Een beetje instellen
Gebruik de bitsgewijze OR-operator (|
) om een bit in te stellen.
number |= 1UL << n;
Dat zal het n
de bit van number
instellen. n
moet nul zijn, als u de 1
ste bit enzovoort wilt instellen tot n-1
, als u de n
de bit.
Gebruik 1ULL
als number
breder is dan unsigned long
; promotie van 1UL << n
gebeurt pas na evaluatie van 1UL << n
waarbij het ongedefinieerd gedrag is om meer dan de breedte van een long
te verschuiven. Hetzelfde geldt voor alle andere voorbeelden.
Een beetje opruimen
Gebruik de bitsgewijze AND-operator (&
) om een bit te wissen.
number &= ~(1UL << n);
Dat zal het n
de bit van number
wissen. U moet de bitreeks omkeren met de bitsgewijze NOT-operator (~
), en vervolgens EN.
Een beetje schakelen
De XOR-operator (^
) kan worden gebruikt om een bit te wisselen.
number ^= 1UL << n;
Dat zal het n
de bit van number
omschakelen.
Een beetje controleren
Je hebt hier niet om gevraagd, maar ik kan het net zo goed toevoegen.
Om een bit te controleren, verschuift u het getal n naar rechts en vervolgens bitsgewijs EN:
bit = (number >> n) & 1U;
Dat zal de waarde van de n
TH-bit van number
in de variabele bit
plaatsen.
De N TH-bit naar X
wijzigen
Instellen van de n
TH Bit tot of 1
of 0
kan worden bereikt met het volgende op de complement C++ implementatie van A2:
number ^= (-x ^ number) & (1UL << n);
Bit n
WORDT INDIEND INDIEN x
1
, en gewist indien x
0
. Als x
een andere waarde heeft, krijgt u afval. x = !!x
ZAL HET BOOLOOLISEREN OP 0 OF 1.
Om dit onafhankelijk te maken van 2’s complement ontkenninggedrag (waarbij -1
alle bits set heeft, in tegenstelling tot een 1-aanvulling of het teken / magnitude C++ implementatie / magnitude C++), gebruikt u niet-ondertekende negatie.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
of
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
Het is over het algemeen een goed idee om niet-ondertekende typen te gebruiken voor draagbare bitmanipulatie.
of
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
ZAL DE n
TH BIT EN (x << n)
ZELt de n
TH BIT NAAR x
.
Het is over het algemeen ook een goed idee om in het algemeen geen code te kopiëren/plakken en daarom gebruiken veel mensen preprocessor-macro’s (zoals de community-wiki antwoord verderop) of een soort van inkapseling.
Antwoord 2, autoriteit 13%
De standaard C++-bibliotheek gebruiken: std::bitset<N>
.
Of de Boost-versie: boost::dynamic_bitset
.
Het is niet nodig om zelf te rollen:
#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
De Boost-versie maakt een runtime-bitset mogelijk in vergelijking met een standaardbibliotheek-compilatie -bitset ter grootte van de tijd.
Antwoord 3, autoriteit 7%
De andere optie is om bitvelden te gebruiken:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
definieert een 3-bits veld (eigenlijk zijn het drie 1-bits velden). Bitbewerkingen worden nu een beetje (haha) eenvoudiger:
Een beetje instellen of wissen:
mybits.b = 1;
mybits.c = 0;
Een beetje wisselen:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
Een beetje controleren:
if (mybits.c) //if mybits.c is non zero the next line below will execute
Dit werkt alleen met bitvelden met een vaste grootte. Anders moet je je toevlucht nemen tot de bit-twiddling-technieken die in eerdere berichten zijn beschreven.
Antwoord 4, autoriteit 5%
Ik gebruik macro’s die zijn gedefinieerd in een headerbestand om bitset en clear te verwerken:
/* 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
#define BITMASK_SET(x, mask) ((x) |= (mask))
#define BITMASK_CLEAR(x, mask) ((x) &= (~(mask)))
#define BITMASK_FLIP(x, mask) ((x) ^= (mask))
#define BITMASK_CHECK_ALL(x, mask) (!(~(x) & (mask)))
#define BITMASK_CHECK_ANY(x, mask) ((x) & (mask))
Antwoord 5, autoriteit 3%
Het is soms de moeite waard om een enum
te gebruiken om de bits een naam te geven:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
Gebruik dan later de namen. D.w.z. schrijf
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
in te stellen, te wissen en te testen. Op deze manier verberg je de magische getallen voor de rest van je code.
Voor de rest onderschrijf ik Jeremy’s oplossing.
Antwoord 6
Van snip-c.zip‘s bitops.h:
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/
typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;
#define BOOL(x) (!(!(x)))
#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))
Ok, laten we de dingen analyseren…
De algemene uitdrukking waarmee u problemen lijkt te hebben in al deze is “(1L << (posn))”. Het enige dat dit doet, is een masker maken met een enkele bit aan
en die zal werken met elk type geheel getal. Het argument “posn” specificeert de
positie waar u het bit wilt hebben. Als posn==0, dan zal deze uitdrukking
evalueren naar:
0000 0000 0000 0000 0000 0000 0000 0001 binary.
Als posn==8, wordt het geëvalueerd als:
0000 0000 0000 0000 0000 0001 0000 0000 binary.
Met andere woorden, het creëert eenvoudig een veld van nullen met een 1 op de opgegeven waarde
positie. Het enige lastige deel is in de BitClr()-macro waar we moeten instellen
een enkele 0 bit in een veld van enen. Dit wordt bereikt door gebruik te maken van de enen
complement van dezelfde uitdrukking zoals aangegeven door de tilde (~) operator.
Zodra het masker is gemaakt, wordt het op het argument toegepast, precies zoals u voorstelt,
door gebruik van de bitsgewijze en (&), of (|), en xor (^) operators. Sinds het masker
van het type long is, werken de macro’s net zo goed op char’s, short’s, int’s,
of lang.
Het komt erop neer dat dit een algemene oplossing is voor een hele klasse van
problemen. Het is natuurlijk mogelijk en zelfs passend om de
equivalent van een van deze macro’s met expliciete maskerwaarden elke keer dat u
heb er een nodig, maar waarom zou je het doen? Onthoud dat de macrovervanging plaatsvindt in de
preprocessor en dus zal de gegenereerde code het feit weerspiegelen dat de waarden
worden door de compiler als constant beschouwd – d.w.z. het is net zo efficiënt om te gebruiken
de gegeneraliseerde macro’s om “het wiel opnieuw uit te vinden” elke keer dat je moet doen
beetje manipulatie.
Niet overtuigd? Hier is wat testcode – ik heb Watcom C gebruikt met volledige optimalisatie
en zonder _cdecl te gebruiken, zou de resulterende demontage zo schoon zijn als
mogelijk:
—-[ 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 (gedemonteerd) ]———————————– ————
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
—-[ eind ]—————————————- ————————-
Antwoord 7
Voor de beginner wil ik graag wat meer uitleg geven met een voorbeeld:
Voorbeeld:
value is 0x55;
bitnum : 3rd.
De operator &
wordt gebruikt, controleer de bit:
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)
Toggle of Flip:
0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)
|
operator: stel de bit in
0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
Antwoord 8
Aangezien dit is getagd met “embedded”, neem ik aan dat je een microcontroller gebruikt. Alle bovenstaande suggesties zijn geldig & werk (lezen-wijzig-schrijven, vakbonden, structs, enz.).
Tijdens een op oscilloscoop gebaseerde debugging was ik echter verbaasd te ontdekken dat deze methoden een aanzienlijke overhead in CPU-cycli hebben in vergelijking met het rechtstreeks schrijven van een waarde naar de PORTnSET / PORTnCLEAR-registers van de micro, wat een echt verschil maakt waar er krappe lussen / hoogfrequente ISR-wisselpinnen.
Voor degenen die niet bekend zijn: in mijn voorbeeld heeft de micro een algemeen pin-state register PORTn dat de uitvoerpinnen weerspiegelt, dus PORTn |= BIT_TO_SET resulteert in een read-modify-write naar dat register. Echter, de PORTnSET / PORTnCLEAR registers nemen een ‘1’ voor “maak dit bit 1” (SET) of “maak dit bit nul” (CLEAR) en een ‘0’ betekent “laat de pin met rust”. je krijgt dus twee poortadressen, afhankelijk van of je de bit instelt of opruimt (niet altijd handig), maar een veelsnellere reactie en kleinere geassembleerde code.
Antwoord 9
Hier is mijn favoriete bit rekenkundige macro, die werkt voor elk type unsigned integer array van unsigned char
tot size_t
(wat het grootste type is dat efficiënt zou moeten zijn om werken met):
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))
Een beetje instellen:
BITOP(array, bit, |=);
Om een beetje duidelijk te maken:
BITOP(array, bit, &=~);
Een beetje wisselen:
BITOP(array, bit, ^=);
Een beetje testen:
if (BITOP(array, bit, &)) ...
enz.
Antwoord 10
De bitfield-benadering heeft nog andere voordelen in de embedded arena. U kunt een structuur definiëren die rechtstreeks op de bits in een bepaald hardwareregister wordt afgebeeld.
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;
Je moet je bewust zijn van de volgorde van het inpakken van bits – ik denk dat het eerst MSB is, maar dit kan afhankelijk zijn van de implementatie. Controleer ook hoe uw compiler-handlers velden overschrijden die bytegrenzen overschrijden.
U kunt dan de afzonderlijke waarden lezen, schrijven en testen zoals voorheen.
Antwoord 11
Controleer een beetje op een willekeurige locatie in een variabele van willekeurig type:
#define bit_test(x, y) ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
Voorbeeld van gebruik:
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;
}
Opmerkingen:
Dit is ontworpen om snel (gezien de flexibiliteit) en niet-vertakt te zijn. Het resulteert in efficiënte SPARC-machinecode wanneer Sun Studio 8 wordt gecompileerd; Ik heb het ook getest met MSVC++ 2008 op amd64. Het is mogelijk om vergelijkbare macro’s te maken voor het instellen en wissen van bits. Het belangrijkste verschil van deze oplossing in vergelijking met vele andere hier is dat het voor elke locatie in vrijwel elk type variabele werkt.
Antwoord 12
Algemeen, voor bitmaps van willekeurige grootte:
#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)))
13
Dit programma is om alle gegevensbit van 0 tot 1 of 1 tot 0 te wijzigen:
{
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);
}
}
}
14
Gebruik dit:
int ToggleNthBit ( unsigned char n, int num )
{
if(num & (1 << n))
num &= ~(1 << n);
else
num |= (1 << n);
return num;
}
15
Als je veel bit twiddling doet, wil je misschien maskers gebruiken die het hele ding sneller maken. De volgende functies zijn erg snel en zijn nog steeds flexibel (ze staan bit twiddling toe in bitkaarten van elke grootte).
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;
}
Let op, om bit ‘n’ in te stellen in een 16 bit integer doe je het volgende:
TSetBit( n, &my_int);
Het is aan jou om ervoor te zorgen dat het bitnummer binnen het bereik ligt van de bitmap die je doorgeeft. Merk op dat voor kleine endian-processors die bytes, woorden, dwords, qwords, enz. correct aan elkaar in het geheugen worden toegewezen (de belangrijkste reden dat kleine endian-processors ‘beter’ zijn dan big-endian-processors, ah, ik voel een vlammenoorlog aankomen aan…).
Antwoord 16
Uitbreiding van het antwoord 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;
}
Antwoord 17
Laten we eerst een paar dingen veronderstellen
num = 55
Geheel getal om bitsgewijze bewerkingen uit te voeren (set, get, clear, toggle).
n = 4
0 gebaseerde bitpositie om bitsgewijze bewerkingen uit te voeren.
Hoe krijg je een beetje?
- Om het
nth
bit van num naar rechts te verschuiven, verschuift unum
,n
keer. Voer vervolgens bitsgewijze AND&
uit met 1.
bit = (num >> n) & 1;
Hoe het werkt?
0011 0111 (55 in decimal)
>> 4 (right shift 4 times)
-----------------
0000 0011
& 0000 0001 (1 in decimal)
-----------------
=> 0000 0001 (final result)
Hoe stel je een bit in?
- Om een bepaald nummer in te stellen. Links shift 1
n
keer. Voer vervolgens een bitsgewijze OF|
-bewerking uit metnum
.
num |= (1 << n); // Equivalent to; num = (1 << n) | num;
Hoe het werkt?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
| 0011 0111 (55 in decimal)
-----------------
=> 0001 0000 (final result)
Hoe een beetje wissen?
- Linker shift 1,
n
keer, d.w.z.1 << n
. - Voer bitsgewijze aanvulling uit met het bovenstaande resultaat. Zodat de n-de bit wordt uitgeschakeld en de rest van de bit wordt ingesteld, d.w.z.
~ (1 << n)
. - Voer ten slotte de bitsgewijze AND
&
bewerking uit met het bovenstaande resultaat ennum
. De bovenstaande drie stappen samen kunnen worden geschreven alsnum & (~ (1 << n))
;
num &= (~(1 << n)); // Equivalent to; num = num & (~(1 << n));
Hoe het werkt?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
~ 0001 0000
-----------------
1110 1111
& 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
Hoe een beetje te schakelen?
Om een beetje te schakelen, gebruiken we bitwise XOR ^
Operator. Bitwise XOR-operator evalueert naar 1 als het overeenkomstige bit van beide operanden anders zijn, anders evalueert op 0.
Wat betekent om een beetje te schakelen, we moeten XOR-werking uitvoeren met het bit dat u wilt schakelen en 1.
num ^= (1 << n); // Equivalent to; num = num ^ (1 << n);
Hoe het werkt?
- Als het bit om te schakelen 0 is, dan,
0 ^ 1 => 1
. - Als het bit om te schakelen 1 dan is,
1 ^ 1 => 0
.
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
^ 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
Aanbevolen lezen – bitwise exploitant oefeningen
18
Visual C 2010, en misschien hebben veel andere compilers, directe ondersteuning voor Boolean-operaties ingebouwd. Een beetje heeft twee mogelijke waarden, net als een boolean, zodat we Booleans in plaats daarvan kunnen gebruiken – zelfs als ze meer ruimte in beslag nemen dan een beetje in het geheugen in deze representatie. Dit werkt, zelfs de sizeof()
operator werkt goed.
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);
}
Dus, op uw vraag, IsGph[i] =1
, of IsGph[i] =0
maken het instellen en wissen van bools eenvoudig.
Onafdrukbare tekens zoeken:
// 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;
}
}
Let op: er is niets “speciaals” aan deze code. Het behandelt een beetje als een geheel getal – wat technisch gezien ook zo is. Een 1-bits geheel getal dat 2 waarden kan bevatten, en slechts 2 waarden.
Ik heb deze benadering ooit gebruikt om dubbele leenrecords te vinden, waarbij leennummer de ISAM-sleutel was, waarbij ik het 6-cijferige leennummer gebruikte als een index in de bitarray. Razendsnel en na 8 maanden bleek dat het mainframesysteem waarvan we de gegevens kregen, in feite niet goed functioneerde. De eenvoud van bit-arrays maakt het vertrouwen in hun correctheid erg hoog – in vergelijking met een zoekbenadering bijvoorbeeld.
Antwoord 19
Als je deze hele bewerking wilt uitvoeren met C-programmering in de Linux-kernel, raad ik aan om standaard API’s van de Linux-kernel te gebruiken.
Zie 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
Opmerking: hier gebeurt de hele operatie in één stap. Dus deze zijn allemaal gegarandeerd atomair, zelfs op SMP-computers en zijn nuttig
om de samenhang tussen processors te behouden.
Antwoord 20
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);
}
Antwoord 21
Hier zijn enkele macro’s die ik gebruik:
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
Dit programma is gebaseerd op de bovenstaande oplossing van @ Jeremy. Als iemand snel wil spelen.
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
23
Een gemanoneerde versie (in een header-bestand) met ondersteuning voor het wijzigen van meerdere bits (Works on AVR Microcontrollers BTW):
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...));}
}
Voorbeeld van gebruik:
#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: het blijkt dat constexpr en inline niet worden gebruikt als het optimalisatieargument (bijvoorbeeld: -O3) niet naar de compiler wordt verzonden. Probeer de code gerust uit op https://godbolt.org/en bekijk de ASM-uitvoer.
Antwoord 24
De n-de bit instellen op x (bitwaarde) zonder -1 te gebruiken
Soms, als je niet zeker weet wat -1 of iets dergelijks zal opleveren, wil je misschien de n-de bit instellen zonder -1 te gebruiken:
number = (((number | (1 << n)) ^ (1 << n))) | (x << n);
Uitleg: ((number | (1 << n)
stelt de n-de bit in op 1 (waarbij |
bitsgewijze OR is), vervolgens met (...) ^ (1 << n)
we zetten de n-de bit op 0, en tot slot met (...) | x << n)
we stel de n-de bit die 0 was, in op (bitwaarde) x
.
Dit werkt ook in golang
.
Antwoord 25
Hier is een routine in C om de basis bitsgewijze bewerkingen uit te voeren:
#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;
}
Antwoord 26
Probeer een van deze functies in de C-taal om n bit te veranderen:
char bitfield;
// Start at 0th position
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}
of
void chang_n_bit(int n, int value)
{
bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}
of
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;
}