Hoe stel, wis en schakel je een enkele bit in?

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 nde bit van numberinstellen. nmoet nul zijn, als u de 1ste bit enzovoort wilt instellen tot n-1, als u de nde bit.

Gebruik 1ULLals numberbreder is dan unsigned long; promotie van 1UL << ngebeurt pas na evaluatie van 1UL << nwaarbij het ongedefinieerd gedrag is om meer dan de breedte van een longte 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 nde bit van numberwissen. 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 nde bit van numberomschakelen.

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 nTH-bit van numberin de variabele bitplaatsen.

De N TH-bit naar X

wijzigen

Instellen van de nTH Bit tot of 1of 0kan worden bereikt met het volgende op de complement C++ implementatie van A2:

number ^= (-x ^ number) & (1UL << n);

Bit nWORDT INDIEND INDIEN x1, en gewist indien x0. Als xeen andere waarde heeft, krijgt u afval. x = !!xZAL HET BOOLOOLISEREN OP 0 OF 1.

Om dit onafhankelijk te maken van 2’s complement ontkenninggedrag (waarbij -1alle 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 nTH BIT EN (x << n)ZELt de nTH 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 enumte 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 chartot 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 = 55Geheel getal om bitsgewijze bewerkingen uit te voeren (set, get, clear, toggle).
n = 40 gebaseerde bitpositie om bitsgewijze bewerkingen uit te voeren.

Hoe krijg je een beetje?

  1. Om het nthbit van num naar rechts te verschuiven, verschuift u num, nkeer. 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?

  1. Om een bepaald nummer in te stellen. Links shift 1 nkeer. Voer vervolgens een bitsgewijze OF |-bewerking uit met num.
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?

  1. Linker shift 1, nkeer, d.w.z. 1 << n.
  2. 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).
  3. Voer ten slotte de bitsgewijze AND &bewerking uit met het bovenstaande resultaat en num. De bovenstaande drie stappen samen kunnen worden geschreven als num & (~ (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] =0maken 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;
}

Other episodes