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


2566

आप कैसे सेट, स्पष्ट और थोड़ा टॉगल कर सकते हैं?


63
इसे पढ़ें: graphics.stanford.edu/~seander/bithacks.html और जब आप इसे मास्टर करेंगे, तो इसे एक पढ़ें: realtimecollisiondetection.net/blog/?p=78
ugasoft

9
आपको बिट टिडलर , बिट ट्विडलिंग हैक्स , और द एग्रीगेट मैजिक एल्गोरिदम की जांच करने में भी रुचि हो सकती है ।

जवाबों:


3594

थोडा सेटिंग करना

|बिट सेट करने के लिए बिटवाइज़ OR ऑपरेटर ( ) का उपयोग करें ।

number |= 1UL << n;

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

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

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

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

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

यही कारण है कि साफ हो जाएगा nकी वें बिट number। आपको बिटवे नॉट ऑपरेटर ( ~) के साथ बिट स्ट्रिंग को पलटना होगा , और फिर इसे।

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

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

number ^= 1UL << n;

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

थोड़ा जाँच कर रहा है

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

एक बिट की जांच करने के लिए, संख्या n को दाईं ओर शिफ्ट करें, फिर बिटवाइज़ और इसे:

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

यह nवें बिट के मूल्य numberको चर में डाल देगा bit

N वें बिट को x में बदलना

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

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

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

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

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

या

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

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

या

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

(number & ~(1UL << n))साफ हो जाएगा nवें बिट और (x << n)सेट हो जाएगा nकरने के लिए वें बिट x

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


127
मैं यह नोट करना चाहूंगा कि बिट सेट / क्लियर (पूर्व, AVR माइक्रोकंट्रोलर) के लिए देशी समर्थन वाले प्लेटफार्मों पर, कंपाइलर अक्सर 'myByte | = (1 << x)' को मूल बिट सेट / स्पष्ट निर्देशों में अनुवाद करेंगे जब भी x। एक स्थिर, पूर्व: (1 << 5), या कास्ट अहस्ताक्षरित x = 5.
हारून

52
बिट = संख्या & (1 << x); जब तक बिट में _Bool (<stdbool.h>) टाइप नहीं होगा, तब तक बिट x का मान नहीं रखा जाएगा। अन्यथा, बिट = !! (संख्या और (1 << x)); होगा ..
क्रिस यंग

23
आप अंतिम एक को क्यों नहीं बदलतेbit = (number >> x) & 1
aaronman

42
1एक intशाब्दिक है, जिस पर हस्ताक्षर किए गए हैं। इसलिए यहां सभी ऑपरेशन हस्ताक्षरित संख्याओं पर काम करते हैं, जो मानकों द्वारा अच्छी तरह से परिभाषित नहीं है। मानकों को दो के पूरक या अंकगणितीय बदलाव की गारंटी नहीं है, इसलिए इसका उपयोग करना बेहतर है 1U
सियुआन रेन

50
मैं number = number & ~(1 << n) | (x << n);n-वें बिट को x में बदलना पसंद करता हूं ।
जियासी

459

मानक C ++ लाइब्रेरी का उपयोग करना: std::bitset<N> :।

या बूस्ट संस्करण:boost::dynamic_bitset :।

अपना स्वयं का रोल करने की कोई आवश्यकता नहीं है:

#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

बूस्ट संस्करण मानक लाइब्रेरी कंपाइल-टाइम आकार बिटसेट की तुलना में रनटाइम आकार बिटसेट की अनुमति देता है ।


34
+1। ऐसा नहीं है कि एसटीडी: बिटसेट "सी" से प्रयोग करने योग्य है, लेकिन जैसा कि लेखक ने "सी ++", एएफएआईके के साथ अपने प्रश्न को टैग किया है, आपका उत्तर यहां के आसपास सबसे अच्छा है ... एसटीडी :: वेक्टर <बूल> एक और तरीका है, अगर किसी को इसके पेशेवरों और इसके विपक्ष के बारे में पता है
paercebal

23
@andrewdotnich: वेक्टर <bool> (दुर्भाग्य से) एक विशेषज्ञता है जो मूल्यों को बिट्स के रूप में संग्रहीत करता है। देखें gotw.ca/publications/mill09.htm अधिक जानकारी के लिए ...
निकलस

71
हो सकता है कि किसी ने इसका उल्लेख न किया हो क्योंकि यह टैग किया हुआ था। अधिकांश एम्बेडेड सिस्टम में आप प्लेग की तरह एसटीएल से बचते हैं। और बढ़ावा समर्थन सबसे एम्बेडेड संकलक के बीच हाजिर करने के लिए एक बहुत ही दुर्लभ पक्षी होने की संभावना है।
लुंडिन

17
@ मॉर्टिन यह बहुत सच है। एसटीएल और टेम्पलेट्स जैसे विशिष्ट प्रदर्शन हत्यारों के अलावा, कई एम्बेडेड सिस्टम भी पूरी तरह से पूरे मानक पुस्तकालयों से बचते हैं, क्योंकि वे इस तरह के दर्द को सत्यापित करने के लिए हैं। अधिकांश एम्बेडेड शाखा MISRA जैसे मानकों को गले लगा रही है, जिसके लिए स्थैतिक कोड विश्लेषण टूल की आवश्यकता होती है (किसी भी सॉफ्टवेयर पेशेवरों को ऐसे उपकरण btw का उपयोग करना चाहिए, न कि केवल एम्बेडेड लोग)। आम तौर पर लोगों के पास पूरे मानक पुस्तकालय के माध्यम से स्थैतिक विश्लेषण चलाने की तुलना में बेहतर चीजें होती हैं - यदि इसका स्रोत कोड उन्हें विशिष्ट संकलक पर भी उपलब्ध है।
लुंडिन

37
@ लुंडिन: आपके कथन अत्यधिक व्यापक हैं (इस प्रकार बहस करना बेकार है)। मुझे यकीन है कि मैं पा सकता हूं कि वे परिस्थितियां सच थीं। यह मेरा प्रारंभिक बिंदु नहीं बदलता है। एम्बेडेड सिस्टम में उपयोग के लिए ये दोनों कक्षाएं पूरी तरह से ठीक हैं (और मैं इस तथ्य के लिए जानता हूं कि उनका उपयोग किया जाता है)। एम्बेडेड सिस्टम पर एसटीएल / बूस्ट का उपयोग नहीं करने के बारे में आपका प्रारंभिक बिंदु भी गलत है। मुझे यकीन है कि ऐसे सिस्टम हैं जो उनका उपयोग नहीं करते हैं और यहां तक ​​कि सिस्टम जो उनका उपयोग करते हैं वे विवेकपूर्ण तरीके से उपयोग किए जाते हैं, लेकिन यह कहना कि उनका उपयोग नहीं किया जाता है, केवल सही नहीं है (क्योंकि सिस्टम हैं उनका उपयोग किया जाता है)।
मार्टिन यॉर्क

248

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

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

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


68
मैंने हमेशा पाया है कि bitfields का उपयोग करना एक बुरा विचार है। आपके पास उस क्रम पर कोई नियंत्रण नहीं है जिसमें बिट्स (ऊपर या नीचे से) आवंटित किए जाते हैं, जो बिट-ए-टाइम को छोड़कर स्थिर / पोर्टेबल तरीके से मूल्य को क्रमबद्ध करना असंभव बनाता है। बिटफ़िल्ड के साथ DIY बिट अंकगणित को मिश्रण करना भी असंभव है, उदाहरण के लिए एक मुखौटा बनाना जो एक साथ कई बिट्स के लिए परीक्षण करता है। आप निश्चित रूप से && का उपयोग कर सकते हैं और आशा करते हैं कि कंपाइलर इसे सही ढंग से ऑप्टिमाइज़ करेगा ...
R .. GitHub STOP HELPING ICE

34
बहुत सारे क्षेत्रों में खराब क्षेत्र हैं, मैं इसके बारे में एक किताब लिख सकता हूं। वास्तव में मुझे लगभग थोड़ा सा क्षेत्र कार्यक्रम के लिए ऐसा करना पड़ा जिसके लिए MISRA-C अनुपालन की आवश्यकता थी। MISRA-C सभी कार्यान्वयन-परिभाषित व्यवहार को प्रलेखित करने के लिए लागू करता है, इसलिए मैंने हर चीज के बारे में काफी निबंध लिखना समाप्त कर दिया जो कि बिट क्षेत्रों में गलत हो सकता है। बिट ऑर्डर, एंडियन, पैडिंग बिट्स, पैडिंग बाइट्स, विभिन्न अन्य संरेखण मुद्दे, बिट क्षेत्र से और यूबीबी से अंतर्निहित और स्पष्ट प्रकार के रूपांतरण, अगर इंट का उपयोग नहीं किया जाता है और इसी तरह। इसके बजाय, कम बग और पोर्टेबल कोड के लिए बिटवाइज़-ऑपरेटर्स का उपयोग करें। बिट क्षेत्र पूरी तरह से बेमानी हैं।
लुंडिन

44
अधिकांश भाषा सुविधाओं की तरह, बिट फ़ील्ड का सही उपयोग किया जा सकता है या उनका दुरुपयोग किया जा सकता है। यदि आपको कई छोटे मूल्यों को एक ही इंट में पैक करने की आवश्यकता है, तो बिट फ़ील्ड बहुत उपयोगी हो सकते हैं। दूसरी ओर, यदि आप इस बारे में धारणा बनाना शुरू करते हैं कि बिट फ़ील्ड कैसे वास्तविक इंट में मैप करते हैं, तो आप केवल परेशानी पूछ रहे हैं।
फेर्रुकियो

4
@endolith: यह एक अच्छा विचार नहीं होगा। आप इसे काम कर सकते हैं, लेकिन यह आवश्यक रूप से एक अलग प्रोसेसर, या एक अलग संकलक या यहां तक ​​कि एक ही संकलक की अगली रिलीज के लिए पोर्टेबल नहीं होगा।
फेरुचियो

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

181

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

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

17
उह मुझे लगता है कि यह एक 5 साल पुरानी पोस्ट है, लेकिन उन मैक्रों, डैन में से किसी में भी कोई दोहराव नहीं है, डैन
रॉबर्ट केली

11
BITMASK_CHECK(x,y) ((x) & (y))होना चाहिए ((x) & (y)) == (y)अन्यथा यह multibit मुखौटा पर गलत परिणाम देता है (उदा। 5बनाम 3/ * हैलो सभी कब्र खोदने के लिए:) * /)
Brigadir

7
1(uintmax_t)1अगर किसी को इन मैक्रोज़ को longबड़े या बड़े प्रकार पर इस्तेमाल करने की कोशिश करनी चाहिए
MM

2
BITMASK_CHECK_ALL(x,y)के रूप में लागू किया जा सकता है!~((~(y))|(x))
Handy999

3
@ Handy999 यह देखना थोड़ा आसान है कि डी मॉर्गन के कानून को लागू करने और फिर से प्राप्त करने के लिए फिर से काम करने के लिए क्यों काम करता है!(~(x) & (y))
Tavian Barnes

114

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

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

फिर बाद में नामों का उपयोग करें । यानी लिखना

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

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

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


1
वैकल्पिक रूप से आप clearbits()इसके बजाय एक समारोह बना सकते हैं &= ~। आप इसके लिए एनम का उपयोग क्यों कर रहे हैं? मुझे लगता है कि वे छिपे हुए मनमाने मूल्य के साथ अद्वितीय चर का एक गुच्छा बनाने के लिए थे, लेकिन आप प्रत्येक को एक निश्चित मूल्य प्रदान कर रहे हैं। तो क्या लाभ है बनाम सिर्फ उन्हें चर के रूप में परिभाषित करना?
एंडोलिथ 15

4
@endolith: enumसंबंधित स्थिरांक के सेट के लिए s का उपयोग c प्रोग्रामिंग में एक लंबा रास्ता तय करता है। मुझे संदेह है कि आधुनिक कंपाइलरों के साथ const shortया केवल जो भी लाभ है, वह स्पष्ट रूप से एक साथ समूहीकृत है। और जब आप उन्हें बिटमास्क के अलावा किसी और चीज के लिए चाहते हैं तो आपको स्वचालित नंबर मिल जाता है। सी ++ में, वे अलग-अलग प्रकार भी बनाते हैं जो आपको थोड़ा एक्स्ट्रा स्टैटिक एरर चेकिंग देता है।
dmckee --- पूर्व-मध्यस्थ ने

यदि आप बिट्स के प्रत्येक संभावित मान के लिए स्थिरांक को परिभाषित नहीं करते हैं, तो आप अपरिभाषित एनम स्थिरांक में मिलेंगे। उदाहरण के लिए enum ThingFlagsमूल्य क्या है ThingError|ThingFlag1?
लुइस कोलोराडो

6
यदि आप इस विधि का उपयोग करते हैं, तो कृपया ध्यान रखें कि एनम स्थिरांक हमेशा हस्ताक्षरित प्रकार के होते हैं int। यह हस्ताक्षरित प्रकारों पर अंतर्निहित पूर्णांक प्रचार या बिटवाइज़ संचालन के कारण सभी प्रकार के सूक्ष्म कीड़े पैदा कर सकता है। thingstate = ThingFlag1 >> 1उदाहरण के लिए कार्यान्वयन-परिभाषित व्यवहार को लागू करेगा। thingstate = (ThingFlag1 >> x) << yअपरिभाषित व्यवहार कर सकते हैं। और इसी तरह। सुरक्षित होने के लिए, हमेशा एक अहस्ताक्षरित प्रकार पर जाएं।
लुंडिन

1
@ लुंडिन: सी ++ 11 के रूप में, आप अंतर्निहित प्रकार की गणना कर सकते हैं, जैसे: enum My16Bits: unsigned short { ... };
ऐकेन ड्रम

47

से 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)))

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

इन सभी में आपको जो सामान्य अभिव्यक्ति दिख रही है, वह है "(1L << (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 बिट सेट करने की आवश्यकता है। यह टिल्ड (~) ऑपरेटर द्वारा निरूपित के समान अभिव्यक्ति के 1 के पूरक का उपयोग करके पूरा किया जाता है।

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

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

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

---- [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 (असंतुष्ट)] -------------------------------------- ---------

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

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


3
इस बारे में 2 बातें: (1) अपने मैक्रोज़ को गलत ठहराने में, कुछ लोग गलत तरीके से यह मान सकते हैं कि मैक्रोज़ वास्तव में सेट / स्पष्ट / फ्लिप बिट्स हैं, हालांकि कोई असाइनमेंट नहीं है; (2) आपका test.c पूरा नहीं हुआ है; मुझे संदेह है कि यदि आप अधिक मामले चलाते हैं तो आपको एक समस्या मिलेगी (पाठक व्यायाम)
Dan

19
-1 यह सिर्फ अजीब बात है। मैक्रोज़ के पीछे भाषा वाक्य रचना को छिपाकर सी भाषा का फिर से आविष्कार न करें, यह बहुत बुरा व्यवहार है। फिर कुछ विषमताएं: पहले, 1L पर हस्ताक्षर किए जाते हैं, जिसका अर्थ है कि सभी बिट ऑपरेशन एक हस्ताक्षरित प्रकार पर किए जाएंगे। इन मैक्रोज़ को दिया गया सब कुछ हस्ताक्षरित लंबे समय के लिए वापस आ जाएगा। अच्छा नही। दूसरा, यह छोटे सीपीयू पर बहुत ही अक्षमता से काम करेगा क्योंकि यह लंबे समय तक लागू होता है जब परिचालन स्तर पर हो सकता था। तीसरा, फ़ंक्शन-जैसे मैक्रोज़ सभी बुराई की जड़ हैं: आपके पास कोई प्रकार की सुरक्षा नहीं है। साथ ही, बिना असाइनमेंट के पिछली टिप्पणी बहुत मान्य है।
लुंडिन

2
अगर argहै तो यह विफल हो जाएगा long long1Lव्यापक संभव प्रकार होने की जरूरत है, इसलिए (uintmax_t)1। (आप दूर हो सकते हैं 1ull)
MM

क्या आपने कोड-आकार के लिए अनुकूलित किया था? इंटेल मुख्यधारा सीपीयू पर आपको इस फ़ंक्शन के लौटने के बाद AX या EAX पढ़ते समय आंशिक-रजिस्टर स्टॉल मिलेगा, क्योंकि यह EAX के 8-बिट घटकों को लिखता है। (यह एएमडी सीपीयू पर ठीक है, या अन्य जो आंशिक रजिस्टर को पूर्ण रजिस्टर से अलग नहीं करते हैं। हैवेल / स्काईलेक एएल को अलग से नाम नहीं देते हैं, लेकिन वे एएच का नाम बदलते हैं। )
पीटर कॉर्डेस

37

बिटवाइज़ ऑपरेटरों का उपयोग करें: & |

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

foo = foo | 001b

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

if ( foo & 001b ) ....

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

foo = foo & 110b

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


7
सी। में कोई बाइनरी नोटेशन नहीं है बाइनरी पूर्णांक स्थिरांक एक गैर-मानक विस्तार है।
लुंडिन

XOR का उपयोग थोड़ा टॉगल करने के लिए करें:foo = foo ^ MY_MASK
पीटर एल

स्पष्ट करने के लिए नकाब को पलटने के लिए उपयोग न करें:foo = foo & ~MY_MASK
पीटर एल

32

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

उदाहरण:

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)

26

यहां मेरा पसंदीदा बिट अंकगणितीय मैक्रो है, जो किसी भी प्रकार के अहस्ताक्षरित पूर्णांक सरणी के लिए काम करता 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, &)) ...

आदि।


5
यह पढ़ना अच्छा है लेकिन किसी को संभावित दुष्प्रभावों के बारे में पता होना चाहिए। BITOP(array, bit++, |=);एक लूप में उपयोग करना सबसे अधिक संभावना नहीं है कि कॉलर क्या चाहता है।
foraidt

वास्तव में। =) एक संस्करण आप पसंद कर सकते हैं 2 मैक्रो, 1 में अलग करने के लिए सरणी तत्व और जगह में बिट के स्थानांतरण के लिए अन्य समाधान के लिए है, आला BITCELL(a,b) |= BITMASK(a,b);(दोनों ले aएक तर्क के रूप आकार निर्धारित करने, लेकिन बाद का मूल्यांकन कभी नहीं होगा aके बाद से यह केवल में दिखाई देता है sizeof)
R .. गिटहब स्टॉप हेल्पिंग ICE

1
@ आर .. यह उत्तर वास्तव में पुराना है, लेकिन मैं शायद इस मामले में एक मैक्रो को एक समारोह पसंद करूंगा।
पीसी लुडाइट

माइनर: 3rd (size_t)डाली हो केवल कुछ बीमा करने के लिए लग रहे अहस्ताक्षरित गणित के साथ %(unsigned)वहाँ हो सकता है।
chux -

(size_t)(b)/(8*sizeof *(a))अनावश्यक रूप से संकीर्ण सकता bविभाजन से पहले। केवल बहुत बड़ी सरणियों के साथ एक मुद्दा। फिर भी एक दिलचस्प मैक्रो।
chux -

25

जैसा कि यह "एम्बेडेड" टैग है, मुझे लगता है कि आप एक माइक्रोकंट्रोलर का उपयोग कर रहे हैं। उपरोक्त सभी सुझाव मान्य हैं और कार्य (रीड-मॉडिफाई-राइट, यूनियन्स, स्ट्रक्चर्स, आदि) हैं।

हालाँकि, आस्टसीलस्कप आधारित डिबगिंग की एक लड़ाई के दौरान मैं यह जानकर चकित रह गया कि इन विधियों में माइक्रो साइकिल के PORTnSET / PORTnCLEAR रजिस्टरों पर सीधे मूल्य लिखने की तुलना में सीपीयू चक्रों में काफी ओवरहेड होता है जो एक वास्तविक अंतर बनाता है जहां तंग छोरों / उच्च होते हैं - ISR की टॉगल पिन।

उन अपरिचितों के लिए: मेरे उदाहरण में, माइक्रो में एक सामान्य पिन-स्टेट रजिस्टर PORTn है जो आउटपुट पिन को दर्शाता है, इसलिए PORTn कर रहा है; = BIT_TO_SET परिणाम को उस रजिस्टर पर रीड-मॉडिफाई-राइट में लिखते हैं। हालाँकि, PORTnSET / PORTnCLEAR रजिस्टर '1' का अर्थ "कृपया इस बिट 1 को बनाएं" (SET) या "कृपया इस बिट को शून्य बनाएं" (CLEAR) और '0' का अर्थ है "पिन को अकेले छोड़ दें"। इसलिए, आप दो पोर्ट एड्रेस के साथ समाप्त होते हैं, इस आधार पर कि आप बिट (हमेशा सुविधाजनक नहीं) सेट या क्लियरिंग कर रहे हैं, लेकिन बहुत तेज़ प्रतिक्रिया और छोटे असेंबल कोड।


कोडवर्ड में सी का उपयोग करके माइक्रो कोल्डफेयर MCF52259 था। Disassembler / asm को देखना एक उपयोगी अभ्यास है क्योंकि यह सभी चरणों को दिखाता है कि सीपीयू को सबसे बुनियादी ऑपरेशन करने के लिए भी गुजरना पड़ता है। <br> हम समय-महत्वपूर्ण छोरों में अन्य सीपीयू-हॉगिंग निर्देशों को भी देखते हैं - वैर% = max_val द्वारा एक चर को विवश करने पर हर बार राउंड में सीपीयू चक्रों का ढेर खर्च होता है, जबकि अगर (var> max_val) var- max_val केवल का उपयोग करता है निर्देश के एक जोड़े। <br> कुछ और ट्रिक्स का एक अच्छा मार्गदर्शक यहाँ है: codeproject.com/Articles/6154/…
जॉन यू

इससे भी महत्वपूर्ण बात, हेल्पर मेमोरी-मैप्ड I / O रजिस्टर परमाणु अद्यतन के लिए एक तंत्र प्रदान करते हैं। यदि अनुक्रम बाधित है तो पढ़ें / संशोधित करें / लिखें बहुत बुरी तरह से जा सकते हैं।
बेन वोइगट

1
ध्यान रखें कि सभी पोर्ट रजिस्टरों को परिभाषित किया जाएगा volatileऔर इसलिए कंपाइलर ऐसे रजिस्टरों को शामिल करने वाले कोड पर कोई अनुकूलन करने में असमर्थ है। इसलिए, इस तरह के कोड को अलग करना अच्छा है और देखें कि यह कोडांतरक स्तर पर कैसे निकला।
लुंडिन

24

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

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;

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

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


2
बिट-फील्ड के बारे में बहुत कुछ सब कुछ कार्यान्वयन-परिभाषित है। यहां तक ​​कि अगर आप सभी विवरणों का पता लगाने का प्रबंधन करते हैं कि आपके विशेष संकलक उन्हें कैसे लागू करते हैं, तो उन्हें अपने कोड में उपयोग करना निश्चित रूप से गैर-पोर्टेबल बना देगा।
लुंडिन

1
@ लुंडिन - सच है, लेकिन एम्बेडेड सिस्टम बिट-फ़िडलिंग (विशेष रूप से हार्डवेयर रजिस्टरों में, जो कि मेरा जवाब संबंधित है) वैसे भी कभी भी उपयोगी पोर्टेबल नहीं होने जा रहा है।
रोडी

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

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

20

मनमाना प्रकार के एक चर में एक मनमाना स्थान पर थोड़ा जाँच करें:

#define bit_test(x, y)  ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

नमूना उपयोग:

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

नोट्स: यह तेजी से (इसकी लचीलेपन को देखते हुए) और गैर-शाखा में बनाया गया है। सन स्टूडियो 8 को संकलित करने पर यह कुशल स्पार्क मशीन कोड में परिणत होता है; मैंने amd64 पर MSVC ++ 2008 का उपयोग करके इसका परीक्षण भी किया है। बिट्स की स्थापना और समाशोधन के लिए समान मैक्रो बनाना संभव है। यहाँ कई अन्य लोगों के साथ तुलना में इस समाधान का मुख्य अंतर यह है कि यह किसी भी स्थान पर किसी भी प्रकार के चर के लिए काम करता है।


20

अधिक सामान्य, मनमाने आकार के बिटमैप के लिए:

#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)))

2
CHAR_BITपहले से परिभाषित है limits.h, आपको अपने आप में डालने की आवश्यकता नहीं है BITS(और वास्तव में ऐसा करने से आप अपना कोड ख़राब कर सकते हैं)
MM

14

यह प्रोग्राम किसी भी डेटा बिट को 0 से 1 या 1 से 0 में बदलने के लिए है:

{
    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

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

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

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


2
किसी ऐसे फ़ंक्शन के लिए तालिका का उपयोग न करें जिसे किसी एकल ऑपरेटर के साथ कार्यान्वित किया जा सकता है। TQuickByteMask [n] (1 << n) के बराबर है। साथ ही, अपने तर्कों को छोटा बनाना बहुत बुरा विचार है। / और% वास्तव में एक विभाजन होगा, बिटशिफ्ट / बिटवाइज़ और नहीं, क्योंकि 2 की शक्ति द्वारा हस्ताक्षरित विभाजन को बिटवाइज़ लागू नहीं किया जा सकता है। आप तर्क प्रकार अहस्ताक्षरित int बनाना चाहिए!
आर .. गिटहब स्टॉप हेल्पिंग ICE

इसका क्या मतलब है? यह केवल कोड को धीमा और पढ़ने में कठिन बनाता है? मैं इसके साथ एक भी लाभ नहीं देख सकता। 1u << n सी प्रोग्रामर के लिए पढ़ना आसान है, और उम्मीद है कि इसे एक ही घड़ी टिक सीपीयू निर्देश में अनुवादित किया जा सकता है। दूसरी ओर, आपका विभाजन 10 टिकों के आसपास किसी चीज़ में अनुवादित किया जाएगा, या यहां तक ​​कि 100 टिकों तक खराब भी हो सकता है, यह इस बात पर निर्भर करता है कि विशिष्ट आर्किटेक्चर कितना खराब तरीके से विभाजन को संभालता है। बिटमैप सुविधा के लिए, गति को ऑप्टिमाइज़ करने के लिए लुकअप तालिका का प्रत्येक बिट इंडेक्स को बाइट इंडेक्स में बदलना अधिक समझ में आता है।
लुंडिन

2
बड़े / छोटे एंडियन के लिए, बड़े एंडियन उसी तरह पूर्णांक और कच्चे डेटा (उदाहरण के तार) को मैप करेंगे: पूरे बिटमैप में lsb पर बाएं से दाएं msb। जबकि थोड़ा एंडियन 7-0, 15-8, 23-18, 31-24 के रूप में दाएं से बाएं पूर्णांक को मैप करेगा, लेकिन कच्चे डेटा अभी भी बाएं से दाएं एमएसबी से एलएसबी तक है। तो आपके विशेष एल्गोरिथ्म के लिए कितना कम एंडियन बेहतर है, पूरी तरह से मेरे से परे है, यह विपरीत प्रतीत होता है।
लुंडिन

2
यदि आपका plattform कुशलता से बदलाव नहीं कर सकते हैं, पुराने माइक्रोचिप एमसीयू की तरह @R .. एक तालिका उपयोगी हो सकता है, लेकिन निश्चित रूप तो नमूने में विभाजन के absolutly अक्षम है
जेब

12

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

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

    return num;
}

5
खैर, यह अकुशल शाखा का उपयोग करता है।
asdf

3
@asdf कम्पाइलर का काम सबसे कुशल बाइनरी का उत्पादन करना है, प्रोग्रामर का काम स्पष्ट कोड लिखना है
एमएम

3
यह परीक्षण, सेटिंग, और किसी विशेष बिट को साफ़ करने का एक अच्छा प्रदर्शन है। हालांकि यह थोड़ा भीख माँगने के लिए एक बहुत बुरा तरीका है।
बेन वोइगट

10

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

10

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

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

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


9

दृश्य C 2010, और शायद कई अन्य संकलक, में निर्मित बूलियन संचालन के लिए प्रत्यक्ष समर्थन है। एक बूलियन की तरह, बिट में दो संभावित मान हैं, इसलिए हम बूलियन का उपयोग कर सकते हैं - भले ही वे एक बिट से अधिक स्थान लेते हों। इस प्रतिनिधित्व में स्मृति। यह काम करता है, यहां तक ​​कि sizeof()ऑपरेटर ठीक से काम करता है।

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 महीनों के बाद, यह साबित हुआ कि हम जिस मेनफ्रेम प्रणाली से डेटा प्राप्त कर रहे थे वह वास्तव में खराबी थी। बिट सरणियों की सादगी उनके शुद्धता में बहुत अधिक विश्वास करती है - उदाहरण के लिए एक खोज दृष्टिकोण बनाम।


एसटीडी :: बिटसेट को वास्तव में अधिकांश
कंपाइलरों

@ कोलिनेट, सहमत। हेडर फ़ाइल #include <bitet> इस संबंध में एक अच्छा संसाधन है। इसके अलावा, विशेष वर्ग वेक्टर <bool> जब आपको वेक्टर के आकार को बदलने की आवश्यकता होती है। सी ++ एसटीएल, दूसरा संस्करण, निकोलाई एम। जोसुतिस क्रमशः उन्हें 650 और 281 पर पीजी पर कवर करता है। सी ++ 11 एसटीडी के कुछ नई क्षमताओं को जोड़ता है :: बिटसेट, मेरे लिए विशेष रुचि अनियंत्रित कंटेनरों में एक हैश फ़ंक्शन है। सर उठाने के लिए धन्यवाद! मैं अपनी दिमागी कमी को दूर करने जा रहा हूँ। पहले से ही वेब पर पर्याप्त कचरा है। मैं इसे जोड़ना नहीं चाहता।

3
यह प्रत्येक के लिए कम से कम भंडारण की एक पूरी बाइट का उपयोग करता है bool। C89 सेटअप के लिए हो सकता है कि यहां तक कि 4 बाइट का उपयोग intलागू करने के लिएbool
एम एम

@MattMcNabb, आप सही हैं। C ++ में बूलियन को लागू करने के लिए आवश्यक इंट प्रकार का आकार मानक द्वारा निर्दिष्ट नहीं है। मुझे एहसास हुआ कि यह उत्तर कुछ समय पहले गलती से था, लेकिन इसे यहां छोड़ने का फैसला किया क्योंकि लोग स्पष्ट रूप से इसे उपयोगी पा रहे हैं। बिट्स गैलीनेट की टिप्पणी का उपयोग करने के इच्छुक लोगों के लिए सबसे अधिक उपयोगी है क्योंकि यहां मेरी बिट लाइब्रेरी है ... stackoverflow.com/a/16534995/1899861

2
@RocketRoy: संभवतः वाक्य को बदलने के लायक है जो यह दावा करता है कि यह "बिट ऑपरेशंस" का एक उदाहरण है।
बेन वोइगट

6

यहां परिभाषित संचालकों में से किसी एक का उपयोग करें

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


2
0xहेक्साडेसिमल में शाब्दिक के लिए उपसर्ग है, न कि बाइनरी।
बेन वोइगट

5

यहाँ कुछ मैक्रोज़ हैं जिनका मैं उपयोग करता हूँ:

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)

5

चर का उपयोग किया

int value, pos;

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

थोड़ा सेट करें:

value = value | 1 << pos;

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

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

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

value = value ^ 1 << pos;

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

वापसी का प्रकार check_nth_bitहो सकता है bool
Xeverous

@Xeverous हाँ यह कॉलर्स के इरादे पर निर्भर करता है
सज्जाद हिसैन खान

5

मान लीजिए कि कुछ चीजें पहले
num = 55 इंटेगर ने बिटवाइज ऑपरेशन (सेट, प्राप्त, स्पष्ट, टॉगल) करने के लिए की हैं।
n = 4बिटवाइज़ ऑपरेशन करने के लिए 0 आधारित बिट स्थिति।

थोड़ा कैसे पाएं?

  1. प्राप्त करने के लिए nthसंख्या सही बदलाव के बिट num, nबार। फिर बिटवाइज़ और &1 के साथ प्रदर्शन करें ।
bit = (num >> n) & 1;

यह काम किस प्रकार करता है?

       0011 0111 (55 in decimal)
    >>         4 (right shift 4 times)
-----------------
       0000 0011
     & 0000 0001 (1 in decimal)
-----------------
    => 0000 0001 (final result)

थोड़ा कैसे सेट करें?

  1. किसी विशेष संख्या को सेट करने के लिए। लेफ्ट शिफ्ट 1 nबार। फिर बिटवाइज़ या |ऑपरेशन करें num
num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

यह काम किस प्रकार करता है?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     | 0011 0111 (55 in decimal)
-----------------
    => 0001 0000 (final result)

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

  1. लेफ्ट शिफ्ट 1, nबार यानी 1 << n
  2. उपरोक्त परिणाम के साथ बिटवाइज पूरक करें। ताकि nth बिट अप्रभावित हो जाए और बाकी बिट सेट हो जाए~ (1 << n)
  3. अंत में, &उपरोक्त परिणाम के साथ बिटवाइज़ और ऑपरेशन करें और num। उपरोक्त तीन चरणों को एक साथ लिखा जा सकता है num & (~ (1 << n));

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

num &= (~(1 << n));    // Equivalent to; num = num & (~(1 << n));

यह काम किस प्रकार करता है?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
     ~ 0001 0000
-----------------
       1110 1111
     & 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

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

बिट को टॉगल करने के लिए हम बिट वाइज XOR ^ऑपरेटर का उपयोग करते हैं । बिटवाइंड XOR ऑपरेटर 1 का मूल्यांकन करता है, यदि दोनों ऑपरेंड के संबंधित बिट अलग-अलग हैं, अन्यथा 0 का मूल्यांकन करता है।

जिसका अर्थ है कि थोड़ा सा टॉगल करें, हमें उस XOR ऑपरेशन को करने की आवश्यकता है जिसमें आप टॉगल करना चाहते हैं और 1।

num ^= (1 << n);    // Equivalent to; num = num ^ (1 << n);

यह काम किस प्रकार करता है?

  • यदि बिट टॉगल 0 है, तो 0 ^ 1 => 1
  • यदि टॉगल करने के लिए 1 है, तो 1 ^ 1 => 0
       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     ^ 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

अनुशंसित पढ़ने - बिटवाइज ऑपरेटर अभ्यास


विस्तृत विवरण के लिए धन्यवाद। यहाँ BIT मैजिक लिंक के लिए अभ्यास की समस्या के लिए लिंक है
चंद्र शेखर

4

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

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

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

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

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

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

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

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

number |= (type_of_number)1 << x;

या धीरे से 1एक गणित ऑपरेशन को मजबूर करके बढ़ावा दें जो कि कम से कम के प्रकार के रूप में व्यापक है number

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

सबसे बिट जोड़तोड़ के साथ, हस्ताक्षरित लोगों के बजाय अहस्ताक्षरित प्रकारों के साथ काम करने के लिए सबसे अच्छा है


एक पुराने सवाल पर दिलचस्प नज़र! साइन किए गए प्रकार के साइन बिट को सेट करने के लिए न तो उचित है number |= (type_of_number)1 << x;और न ही number |= (number*0 + 1) << x;... तथ्य के रूप में, न ही है number |= (1ull << x);। क्या स्थिति के अनुसार इसे करने का एक पोर्टेबल तरीका है?
चकरली

1
IMO @chqrlie, सबसे अच्छा तरीका है पर हस्ताक्षर बिट की स्थापना और बदलाव के साथ यूबी या आईडीबी के जोखिम से बचने के लिए उपयोग करने के लिए है अहस्ताक्षरित प्रकार के। अत्यधिक पोर्टेबल शिफ्ट हस्ताक्षरित कोड स्वीकार्य होने के लिए बहुत जटिल है।
chux -

3

C ++ 11 टेम्प्लेटेड संस्करण (हेडर में रखा गया):

namespace bit {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bit) {variable |=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bit) {variable ^=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);}
}

namespace bitmask {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bits) {variable |= bits;}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bits) {variable &= ~bits;}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bits) {variable ^= bits;}
    template <typename T1, typename T2> inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);}
    template <typename T1, typename T2> inline bool test_any(T1 &variable, T2 bits) {return variable & bits;}
}

यह कोड टूट गया है। (इसके अलावा, आपके पास ;अपने कार्य की परिभाषा के बाद क्यों है ?)
मेलेपोमिन

@melpomene कोड नहीं टूटा है, मैंने इसका परीक्षण किया। क्या आपका मतलब यह है कि यह संकलन नहीं करेगा या इसका परिणाम गलत है? अतिरिक्त के बारे में '?' मुझे याद नहीं है, जिन्हें वास्तव में हटाया जा सकता है।
जोकिम एल। क्रिस्टियनसेन

(variable & bits == bits)?
मेलेपोमिन

ध्यान देने के लिए धन्यवाद, यह होना चाहिए था((variable & bits) == bits)
जोकिम एल। क्रिस्टियनसेन

std::bitsetc ++ 11 में उपयोग करें
pqnet

0

यह कार्यक्रम @ जेरेमी के उपरोक्त समाधान से बाहर है। यदि कोई जल्दी से चारों ओर खेलना चाहता है।

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

-2

सी भाषा में इन कार्यों में से एक को n थोड़ा बदलने की कोशिश करें:

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

value << nअपरिभाषित व्यवहार का कारण हो सकता है
MM
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.