c++ - आप एक बिट को कैसे सेट, साफ़ और टॉगल करते हैं?




bit-manipulation bitwise-operators (18)

आप एक बिट को कैसे सेट, साफ़ और टॉगल करते हैं?

मास्क बनाने का प्रयास करते समय एक सामान्य कोडिंग पिटफॉल को संबोधित करने के लिए:
1हमेशा पर्याप्त चौड़ा नहीं होता है

numberएक व्यापक प्रकार की तुलना में क्या समस्याएं होती हैं 1?
xशिफ्ट के 1 << xलिए अपरिभाषित व्यवहार (यूबी) की ओर अग्रसर होने के लिए बहुत अच्छा हो सकता है । यहां तक ​​कि यदि xबहुत अच्छा नहीं है, तो भी ~पर्याप्त-महत्वपूर्ण-बिट्स को फ़्लिप नहीं कर सकता है।

// assume 32 bit int/unsigned
unsigned long long number = foo();

unsigned x = 40; 
number |= (1 << x);  // UB
number ^= (1 << x);  // UB
number &= ~(1 << x); // UB

x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough

बीमा करने के लिए पर्याप्त चौड़ा है:

कोड उपयोग 1ullया पैडेंटिक रूप से (uintmax_t)1और संकलक अनुकूलित करने दे सकता है।

number |= (1ull << x);
number |= ((uintmax_t)1 << x);

या कास्ट - जो कोड को सही और अद्यतित रखने के लिए कोडिंग / समीक्षा / रखरखाव के मुद्दों के लिए बनाता है।

number |= (type_of_number)1 << x;

या धीरे-धीरे 1गणित के संचालन को मजबूर कर बढ़ावा दें जो कि कम से कम चौड़ा है number

number |= (number*0 + 1) << x;

सबसे अधिक कुशलता के साथ , हस्ताक्षरित लोगों की बजाय हस्ताक्षरित प्रकारों के साथ काम करने के लिए सबसे अच्छा है

सी / सी ++ में थोड़ा सा सेट, साफ़ और टॉगल कैसे करते हैं?


थोड़ा सेट करना

थोड़ा सेट करने के लिए bitwise या ऑपरेटर ( | ) का प्रयोग करें।

number |= 1UL << n;

वह number का n वें सेट सेट करेगा। n शून्य होना चाहिए, यदि आप 1 सेंट बिट सेट करना चाहते हैं और इसलिए n-1 तक, यदि आप n th बिट सेट करना चाहते हैं।

यदि number unsigned long से अधिक व्यापक है तो 1ULL उपयोग करें; 1UL << n का प्रचार 1UL << n मूल्यांकन करने के बाद नहीं होता है, जहां यह long की चौड़ाई से अधिक स्थानांतरित करने के लिए अपरिभाषित व्यवहार है। यह सभी बाकी उदाहरणों पर लागू होता है।

थोड़ा सा साफ़ करना

थोड़ा सा साफ़ करने के लिए bitwise और ऑपरेटर ( & ) का उपयोग करें।

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

यह number के n वें बिट को साफ़ करेगा। आपको बिट स्ट्रिंग को bitwise नहीं ऑपरेटर ( ~ ), फिर और उसके साथ उलटा करना होगा।

थोड़ा टॉगल करना

एक्सओआर ऑपरेटर ( ^ ) का उपयोग थोड़ा टॉगल करने के लिए किया जा सकता है।

number ^= 1UL << n;

वह number के n वें बिट टॉगल करेगा।

थोड़ा सा जांचना

आपने इसके लिए नहीं पूछा था, लेकिन मैं इसे भी जोड़ सकता हूं।

थोड़ा सा जांचने के लिए, संख्या n को दाईं ओर बदलें, फिर bitwise और यह:

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

इससे परिवर्तनीय bit में number के n वें बिट का मान रखा जाएगा।

एन को थोड़ा सा बदलना x

n वें बिट को या तो 1 या 0 सेट करना निम्नलिखित के साथ 2 के पूरक सी ++ कार्यान्वयन पर प्राप्त किया जा सकता है:

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

यदि बिट 1 , तो बिट n सेट किया जाएगा, और अगर x 0 है तो साफ़ हो जाएगा। यदि x पास कुछ अन्य मूल्य है, तो आपको कचरा मिल जाता है। x = !!x इसे 0 या 1 पर बुलियन कर देगा।

इसे 2 के पूरक अस्वीकृति व्यवहार से स्वतंत्र बनाने के लिए (जहां -1 में सभी बिट्स सेट हैं, 1 के पूरक या साइन / परिमाण सी ++ कार्यान्वयन के विपरीत), हस्ताक्षरित अस्वीकरण का उपयोग करें।

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

या

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

पोर्टेबल बिट मैनिपुलेशन के लिए हस्ताक्षर किए गए प्रकारों का उपयोग करना आम तौर पर एक अच्छा विचार है।

आम तौर पर कोड को कॉपी / पेस्ट न करने का भी एक अच्छा विचार है और बहुत से लोग प्रीप्रोसेसर मैक्रोज़ (जैसे समुदाय विकी उत्तर आगे नीचे ) या कुछ प्रकार के encapsulation का उपयोग करते हैं।


snip-c.zip के 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)))

ठीक है, आइए चीजों का विश्लेषण करें ...

आम अभिव्यक्ति जो आपको इनमें से सभी में समस्याएं आ रही हैं "(1 एल << (posn))" है। यह सब एक बिट के साथ एक मुखौटा बना है और जो किसी भी पूर्णांक प्रकार के साथ काम करेगा। "Posn" तर्क उस स्थिति को निर्दिष्ट करता है जहां आप थोड़ा चाहते हैं। यदि posn == 0 है, तो यह अभिव्यक्ति मूल्यांकन करेगी:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

यदि posn == 8, तो इसका मूल्यांकन होगा

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

दूसरे शब्दों में, यह बस निर्दिष्ट स्थिति में 1 के साथ 0 का क्षेत्र बनाता है। एकमात्र मुश्किल हिस्सा बिटक्लर () मैक्रो में है जहां हमें 1 के क्षेत्र में एक 0 बिट सेट करने की आवश्यकता है। यह tilde (~) ऑपरेटर द्वारा बताए गए समान अभिव्यक्ति के 1 के पूरक का उपयोग करके पूरा किया जाता है।

एक बार मास्क बनने के बाद, जैसा कि आप सुझाव देते हैं, बिटवाई और (&), या (|), और xor (^) ऑपरेटरों के उपयोग से, यह तर्क पर लागू होता है। चूंकि मुखौटा लंबा प्रकार का होता है, इसलिए मैक्रोज़ चारों के साथ-साथ चार, शॉर्ट्स, इंट, या लांग पर भी काम करेगा।

निचली पंक्ति यह है कि यह समस्याओं की एक पूरी कक्षा का एक सामान्य समाधान है। यह निश्चित रूप से संभव है, जब भी आपको आवश्यकता हो, स्पष्ट मास्क मानों के साथ इनमें से किसी भी मैक्रोज़ के समकक्ष को फिर से लिखना उचित हो, लेकिन यह क्यों? याद रखें, मैक्रो प्रतिस्थापन प्रीप्रोसेसर में होता है और इसलिए जेनरेट कोड इस तथ्य को प्रतिबिंबित करेगा कि मानकों को स्थिरता द्वारा स्थिर माना जाता है - यानी यह सामान्यीकृत मैक्रोज़ का उपयोग करने के लिए उतना ही कुशल है जितना कि आपको हर बार "पहिया को फिर से शुरू करना" थोड़ा हेरफेर करो।

असंतुष्ट? यहां कुछ टेस्ट कोड हैं - मैंने पूर्ण अनुकूलन के साथ वाटकॉम सी का उपयोग किया और _cdecl का उपयोग किए बिना परिणामस्वरूप डिस्सेप्लर जितना संभव हो उतना साफ होगा:

---- [टेस्ट.सी] ----------------------------------------- -----------------------

#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;
}

---- [टेस्ट.ओयूटी (डिससेम्बल)] -------------------------------------- ---------

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

---- [फिनिस] ------------------------------------------- ----------------------


Bitwise ऑपरेटरों का प्रयोग करें: & |

000b में अंतिम बिट सेट करने के लिए:

foo = foo | 001b

foo में अंतिम बिट की जांच करने के लिए:

if ( foo & 001b ) ....

foo में अंतिम बिट को साफ़ करने के लिए:

foo = foo & 110b

मैंने स्पष्टता के लिए XXXb इस्तेमाल किया। डेटा संरचना के आधार पर आप शायद HEX प्रतिनिधित्व के साथ काम करेंगे, जिसमें आप बिट्स पैक कर रहे हैं।


इसे इस्तेमाल करो:

int ToggleNthBit ( unsigned char n, int num )
{
    if(num & (1 << n))
        num &= ~(1 << n);
    else
        num |= (1 << n);

    return num;
}

कभी-कभी बिट्स नाम देने के लिए एक enum का उपयोग करने लायक है:

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

फिर बाद में नामों का उपयोग करें। मैं लिखता हूँ

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

सेट, स्पष्ट और परीक्षण करने के लिए। इस तरह आप अपने शेष कोड से जादू संख्या छुपाते हैं।

इसके अलावा मैं जेरेमी के समाधान का समर्थन करता हूं।


दूसरा विकल्प बिट फ़ील्ड का उपयोग करना है:

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

एक 3-बिट फ़ील्ड को परिभाषित करता है (वास्तव में, यह तीन 1-बिट फ्लेड्स है)। बिट ऑपरेशन अब थोड़ा सा (हाहा) बन गया है:

थोड़ा सेट या साफ़ करने के लिए:

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

थोड़ा टॉगल करने के लिए:

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

थोड़ा सा जांचना:

if (mybits.c)  //if mybits.c is non zero the next line below will execute

यह केवल निश्चित आकार के बिट फ़ील्ड के साथ काम करता है। अन्यथा आपको पिछली पोस्ट में वर्णित बिट-ट्विडलिंग तकनीकों का सहारा लेना होगा।


बिटफील्ड दृष्टिकोण में एम्बेडेड क्षेत्र में अन्य फायदे हैं। आप एक ऐसी संरचना को परिभाषित कर सकते हैं जो सीधे किसी विशेष हार्डवेयर रजिस्टर में बिट्स पर मैप करें।

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;

आपको बिट पैकिंग ऑर्डर से अवगत होना चाहिए - मुझे लगता है कि यह एमएसबी पहले है, लेकिन यह कार्यान्वयन-निर्भर हो सकता है। साथ ही, सत्यापित करें कि आपके कंपाइलर हैंडलर फ़ील्ड बाइट सीमाओं को पार करते हैं।

फिर आप पहले के रूप में व्यक्तिगत मानों को पढ़, लिख सकते हैं, परीक्षण कर सकते हैं।


मैं बिट सेट को संभालने और साफ़ करने के लिए हेडर फ़ाइल में परिभाषित मैक्रोज़ का उपयोग करता हूं:

/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b))))        // '!!' to make sure this returns 0 or 1

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (((x) & (y)) == (y))   // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))

यदि आप बहुत कम काम कर रहे हैं तो आप मास्क का उपयोग करना चाहेंगे जो पूरी चीज को तेज कर देगा। निम्नलिखित कार्य बहुत तेज़ हैं और अभी भी लचीले हैं (वे किसी भी आकार के बिट मैप्स में बिट ट्विडलिंग की अनुमति देते हैं)।

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;
}

नोट, 16 बिट पूर्णांक में बिट 'n' सेट करने के लिए आप निम्न कार्य करते हैं:

TSetBit( n, &my_int);

यह सुनिश्चित करने के लिए आप पर निर्भर है कि बिट संख्या आपके द्वारा पास किए गए बिट मैप की सीमा के भीतर है। ध्यान दें कि छोटे एंडियन प्रोसेसर जो बाइट्स, शब्द, पासवर्ड, क्वॉर्ड्स इत्यादि के लिए स्मृति में एक-दूसरे के लिए सही ढंग से मानचित्र करते हैं (मुख्य कारण यह है कि छोटे एंडियन प्रोसेसर बड़े-एंडियन प्रोसेसर की तुलना में 'बेहतर' हैं, आह, मुझे एक लौ युद्ध आ रहा है पर...)।


यहां मेरा पसंदीदा बिट अंकगणितीय मैक्रो है, जो किसी भी प्रकार के हस्ताक्षरित पूर्णांक सरणी के लिए unsigned char से size_t तक काम करता है (जो सबसे बड़ा प्रकार है जो काम करने के लिए कुशल होना चाहिए):

#define BITOP(a,b,op) \
 ((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))

थोड़ा सेट करने के लिए:

BITOP(array, bit, |=);

थोड़ा सा साफ़ करने के लिए:

BITOP(array, bit, &=~);

थोड़ा टॉगल करने के लिए:

BITOP(array, bit, ^=);

थोड़ा परीक्षण करने के लिए:

if (BITOP(array, bit, &)) ...

आदि।


शुरुआत के लिए मैं एक उदाहरण के साथ थोड़ा और समझाना चाहता हूं:

उदाहरण:

value is 0x55;
bitnum : 3rd.

ऑपरेटर का उपयोग किया जाता है बिट की जांच करें:

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)

टॉगल या फ्लिप करें:

0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)

| ऑपरेटर: बिट सेट करें

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)

एन बिट बदलने के लिए सी भाषा में इन कार्यों में से किसी एक को आज़माएं:

char bitfield;

// Start at 0th position

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}

या

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}

या

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;
}

परिवर्तनीय इस्तेमाल किया

int value, pos;

मूल्य - डेटा
पॉज़ - बिट की स्थिति जिसे हम सेट करना चाहते हैं, साफ़ करें या टॉगल
करें थोड़ा सेट करें

value = value | 1 << pos;

थोड़ा सा साफ़ करें

value = value & ~(1 << pos); 

थोड़ा टॉगल करें

value = value ^ 1 << pos;

विजुअल सी 2010, और शायद कई अन्य कंपाइलर्स, में निर्मित बिट ऑपरेशंस के लिए सीधा समर्थन है। आश्चर्यजनक रूप से, यह काम करता है, आकार का () ऑपरेटर ठीक से काम करता है।

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);
}

तो, आपके प्रश्न के लिए, IsGph [i] = 1, या IsGph [i] = 0 सेटिंग और साफ़ करने वाले बूल को आसान बनाते हैं।

अप्राप्य पात्र खोजने के लिए ...

//  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;
    }
}

ध्यान दें कि इस कोड के बारे में कुछ भी "विशेष" नहीं है। यह एक पूर्णांक की तरह थोड़ा व्यवहार करता है - जो तकनीकी रूप से, यह है। एक 1 बिट पूर्णांक जो केवल 2 मान, और 2 मान रख सकता है।

मैंने एक बार डुप्लिकेट ऋण रिकॉर्ड खोजने के लिए इस दृष्टिकोण का उपयोग किया, जहां 6-अंकों की ऋण संख्या का उपयोग बिट सरणी में इंडेक्स के रूप में किया गया था, जहां ऋण_नंबर आईएसएएम कुंजी था। सख्ती से तेज़, और 8 महीनों के बाद, साबित हुआ कि जिस मेनफ्रेम सिस्टम से हम डेटा प्राप्त कर रहे थे वह वास्तव में खराब हो रहा था। बिट सरणी की सादगी उनकी शुद्धता में बहुत अधिक आत्मविश्वास बनाती है - उदाहरण के लिए एक खोज दृष्टिकोण बनाम।


here परिभाषित ऑपरेटर में से एक का प्रयोग here

बिट सेट करने के लिए, बाइनरी रूप में बिट स्थिति int x = x | 0x?;कहां उपयोग की ?जाती है।


यदि आप लिनक्स कर्नेल में सी प्रोग्रामिंग के साथ यह सब ऑपरेशन करना चाहते हैं तो मैं लिनक्स कर्नेल के मानक एपीआई का उपयोग करने का सुझाव देता हूं।

https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html देखें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

नोट: यहां पूरा ऑपरेशन एक ही चरण में होता है। इसलिए इन सभी को एसएमपी कंप्यूटरों पर भी परमाणु होने की गारंटी है और प्रोसेसर में समेकन रखने के लिए उपयोगी हैं।


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);
}




bitwise-operators