Vraag Hoe stel je een enkel bit in, wist je het en schakel je het uit?


Hoe stel je in C / C ++ iets in, wist en schakelt het een beetje in?


2048
2017-09-07 00:42


oorsprong


antwoorden:


Een beetje instellen

Gebruik de bitwise OR-operator (|) om een ​​beetje in te stellen.

number |= 1UL << n;

Dat zal de neen beetje number.

Gebruik 1ULL als number is breder dan unsigned long; promotie van 1UL << n gebeurt niet na evaluatie 1UL << n waarbij het ongedefinieerde gedrag verschuift met meer dan de breedte van a long. Hetzelfde geldt voor de rest van de voorbeelden.

Een beetje opruimen

Gebruik de bitwise AND-operator (&) om een ​​beetje leeg te maken.

number &= ~(1UL << n);

Dat zal de neen beetje number. U moet de bitstring omkeren met de bitwise NOT-operator (~), dan EN het.

Een beetje schakelen

De XOR-operator (^) kan worden gebruikt om een ​​beetje te schakelen.

number ^= 1UL << n;

Dat zal de neen beetje number.

Een beetje controleren

Je hebt hier niet om gevraagd, maar ik kan het net zo goed toevoegen.

Als u een beetje wilt controleren, verplaatst u het getal n naar rechts en vervolgens bitwise AND it:

bit = (number >> n) & 1U;

Dat zal de waarde van de neen beetje number in de variabele bit.

De. Wijzigen nbeetje bij beetje X

Het instellen van neen beetje voor beide 1 of 0 kan worden bereikt met het volgende op een 2-complement C ++ implementatie:

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

Beetje n wordt ingesteld als x is 1, en gewist als x is 0. Als x heeft een andere waarde, je krijgt rotzooi. x = !!x zal booleanize het naar 0 of 1.

Om dit onafhankelijk te maken van 2's complementaire negatie gedrag (waar -1 heeft alle bits ingesteld, in tegenstelling tot een 1's complement of teken / magnitude C ++ implementatie), gebruik unsigned negation.

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.

Het is ook over het algemeen een goed idee om in het algemeen geen code te kopiëren en te plakken en zoveel mensen gebruiken preprocessor-macro's (zoals de community-wiki antwoord verderop) of een soort inkapseling.


2997
2017-09-07 00:50



De standaard C ++ -bibliotheek gebruiken: std::bitset<N>.

Of de boost versie: boost::dynamic_bitset.

Het is niet nodig om je eigen 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 bitset in runtime-formaat mogelijk vergeleken met een standaard bibliotheek compilatie-tijd formaat bitset.


381
2017-09-18 00:34



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-bit veld (eigenlijk zijn het drie 1-bit felds). Bitbewerkingen worden nu een beetje (haha) eenvoudiger:

Om een ​​beetje in te stellen of te wissen:

mybits.b = 1;
mybits.c = 0;

Om een ​​beetje te schakelen:

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 van een vast formaat. Anders moet je een beroep doen op de bit-twiddling-technieken die in vorige berichten zijn beschreven.


212
2017-09-11 00:56



Ik gebruik macro's die zijn gedefinieerd in een headerbestand om bitsets 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)))

/* 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))

125
2017-09-08 21:07



Het is soms de moeite waard om een ​​te gebruiken enum naar naam de bits:

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

Gebruik dan de namen later. D.w.z. schrijven

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

instellen, wissen en testen. Op deze manier verberg je de magische nummers van de rest van je code.

Verder onderschrijf ik Jeremy's oplossing.


99
2017-09-17 02:04



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 dingen analyseren ...

De algemene uitdrukking waar je in al deze problemen problemen mee lijkt te hebben is "(1L << (posn))". Dit alles maakt een masker met een enkele bit aan en die werkt met elk type integer. Het "posn" -argument geeft de positie waar u het bit wilt hebben. Als posn == 0 is, dan zal deze expressie evalueren om:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

Als posn == 8, zal het evalueren naar

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

Met andere woorden, het maakt eenvoudig een veld van 0's aan met een 1 op het gespecificeerde positie. Het enige lastige onderdeel is de BitClr () -macro die we moeten instellen een enkele 0 bit in een veld van enen. Dit wordt bereikt door de 1's te gebruiken complement van dezelfde expressie als aangegeven door de tilde (~) -operator.

Nadat het masker is gemaakt, wordt het toegepast op het argument, net zoals u suggereert: door gebruik te maken van de bitsgewijze en (&), of (|), en xof (^) operatoren. Sinds het masker is van het type lang, de macro's zullen net zo goed werken op char's, short's, int's, of lang.

De bottom line is dat dit een algemene oplossing is voor een hele klasse van problemen. Het is natuurlijk mogelijk en zelfs gepast om het equivalent van een van deze macro's met expliciete maskerwaarden elke keer dat u heb je er een nodig, maar waarom? Vergeet niet dat de macrovervanging voorkomt in de preprocessor en dus zal de gegenereerde code het feit weergeven 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 telkens opnieuw het wiel opnieuw uit te vinden bitmanipulatie.

Niet overtuigd? Hier is wat testcode - Ik gebruikte Watcom C met volledige optimalisatie en zonder _cdecl te gebruiken, zodat de resulterende demontage net zo schoon zou 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

---- [finis] ------------------------------------------- ----------------------


34
2018-06-05 14:18



Voor de beginner wil ik een beetje meer uitleggen 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)

28
2017-09-07 00:45



Gebruik de bitsgewijze operatoren: &  | 

Om het laatste bit in te stellen 000b:

foo = foo | 001b

Om de laatste bit in te checken foo:

if ( foo & 001b ) ....

Om het laatste bit in te wissen foo:

foo = foo & 110b

ik gebruikte XXXb voor alle duidelijkheid. U zult waarschijnlijk werken met HEX-weergave, afhankelijk van de gegevensstructuur waarin u bits verpakt.


26
2017-07-13 06:53