examples - the c++ programming language




কিভাবে আপনি সেট, পরিষ্কার, এবং একটি বিট টগল? (18)

কিভাবে আপনি সেট, পরিষ্কার, এবং সি / সি ++ একটি বিট টগল করবেন?


কিভাবে আপনি সেট, পরিষ্কার, এবং একটি বিট টগল?

মুখোশ তৈরি করার চেষ্টা করার সময় একটি সাধারণ কোডিং পিটফল মোকাবেলার জন্য:
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;

সর্বাধিক বিট ম্যানিপুলেশন হিসাবে, স্বাক্ষরিত বেশী বরং স্বাক্ষরিত ধরনের সঙ্গে কাজ করতে


একটি বিট সেট

একটু সেট করতে bitwise OR অপারেটর ( | ) ব্যবহার করুন।

number |= 1UL << n;

যে number n বিট সেট করা হবে। n শূন্য হওয়া উচিত, যদি আপনি 1 ম বিট সেট করতে চান এবং তাই n-1 পর্যন্ত সেট করতে চান তবে n বিট সেট করতে চান।

1ULL যদি 1ULL চেয়ে বৃহত্তর হয় তবে 1ULL ব্যবহার করুন; 1UL << n এর প্রবর্তন 1UL << n মূল্যায়ন না হওয়া পর্যন্ত ঘটবে না যেখানে এটি অনির্ধারিত আচরণ long প্রস্থের চেয়ে বেশি স্থানান্তর করতে পারে। একই উদাহরণ সব বাকি প্রযোজ্য।

একটি বিট ক্লিয়ারিং

বিট পরিষ্কার করার জন্য bitwise এবং অপারেটর ( & ) ব্যবহার করুন।

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

যে number n বিট সাফ হবে। আপনি bitwise নোটি অপারেটর ( ~ ), তারপর এবং এটির সাথে বিট স্ট্রিংকে বিপর্যস্ত করতে হবে।

একটি বিট Toggling

XOR অপারেটর ( ^ ) একটি বিট টগল করতে ব্যবহার করা যেতে পারে।

number ^= 1UL << n;

যে number n বিট টগল হবে।

একটি বিট চেক

আপনি এই জন্য জিজ্ঞাসা না, কিন্তু আমি এটি যোগ করতে পারে।

একটি বিট চেক করার জন্য, নম্বর n ডানদিকে সরান, তারপর বিটwise এবং এটি:

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

যেটি n বিট বিটটির ভেরিয়েবল bit মান দেবে।

এক্স n বি বিট পরিবর্তন

n তম বিট সেট করা হয় 1 বা 0 তে একটি 2 এর সম্পূরক C ++ বাস্তবায়নের সাথে নিম্নলিখিতটি অর্জন করা যেতে পারে:

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

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

পোর্টেবল বিট ম্যানিপুলেশনের জন্য অনির্ধারিত ধরনের ব্যবহার করার জন্য এটি সাধারণত একটি ভাল ধারণা।

সাধারণভাবে কোড অনুলিপি / আটকাতেও এটি ভাল ধারণা নয় এবং তাই অনেকে প্রিপোপ্রসেসার ম্যাক্রো ব্যবহার করে ( সম্প্রদায়ের উইকি উত্তরগুলি আরও নিচে উত্তর দেয় ) বা কিছু ধরণের এনক্যাপুলেশন ব্যবহার করে।


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" যুক্তিটি আপনি বিট চান যেখানে অবস্থান উল্লেখ করে। যদি posn == 0, তাহলে এই অভিব্যক্তি মূল্যায়ন করবে:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

যদি posn == 8, এটা মূল্যায়ন করা হবে

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

অন্য কথায়, এটি কেবল 0 এর একটি ক্ষেত্রকে নির্দিষ্ট অবস্থানে 1 দিয়ে তৈরি করে। একমাত্র চতুর অংশ বিটCl্র () ম্যাক্রোতে যেখানে আমরা 1 এর একটি ক্ষেত্রে একটি বিট 0 বিট সেট করতে হবে। এটি tilde (~) অপারেটর দ্বারা চিহ্নিত হিসাবে একই অভিব্যক্তিটির 1 এর পরিপূরক ব্যবহার করে সম্পন্ন করা হয়।

একবার মাস্ক তৈরি হয়ে গেলে এটি বিটwise এবং (এবং), বা (|), এবং xor (^) অপারেটরগুলির ব্যবহার অনুসারে আপনি যুক্তি হিসাবে প্রয়োগ করেন। যেহেতু মাস্কটি টাইপ লম্বা, তাই ম্যাক্রোগুলি গৃহস্থালি, শর্টস, int এর, বা লম্বায়ও কাজ করবে।

নিচের লাইনটি হ'ল সমস্যাগুলির সম্পূর্ণ শ্রেণীতে এটি একটি সাধারণ সমাধান। এটি অবশ্যই অবশ্যই সম্ভব এবং এমনকি ম্যাক্রোগুলির সমতুল্য পুনর্বিবেচনার জন্য যথাযথ, এমনকি প্রতিবার যখন আপনার দরকার তখন স্পষ্ট মাস্ক মানগুলির সাথে পুনর্লিখন করতে হবে, কিন্তু কেন? মনে রাখবেন, ম্যাক্রো প্রতিস্থাপন প্রিপ্রোসিডারে ঘটে এবং তাই জেনারেটেড কোডটি কম্পাইলার দ্বারা মান্য হিসাবে বিবেচিত হয় - এইভাবে জেনারেটাইজড ম্যাক্রোগুলি ব্যবহার করার জন্য যতটা কার্যকর, প্রতিবার আপনার প্রয়োজন অনুসারে "চাকাটি পুনঃবিবেচনা" হিসাবে কার্যকর বিট ম্যানিপুলেশন না।

অনিশ্চিতপ্রত্যয়? এখানে কিছু পরীক্ষা কোড রয়েছে - আমি সম্পূর্ণ অপটিমাইজেশনের সাথে ওয়াটকম সি ব্যবহার করেছি এবং _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

---- [শেষ] ------------------------------------------- ----------------------


অন্য বিকল্প বিট ক্ষেত্র ব্যবহার করা হয়:

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

struct bits mybits;

একটি 3-বিট ক্ষেত্র নির্ধারণ করে (আসলে, এটি তিনটি-বিট Felds)। বিট অপারেশন এখন একটি বিট (haha) সহজ হয়ে:

একটি বিট সেট বা পরিষ্কার করতে:

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

এই শুধুমাত্র নির্দিষ্ট আকার বিট ক্ষেত্রের সাথে কাজ করে। অন্যথায় আপনি পূর্ববর্তী পোস্টে বর্ণিত বিট-twiddling কৌশল অবলম্বন করা আছে।


আমি বিট সেট এবং পরিষ্কার হ্যান্ডেল করতে একটি হেডার ফাইলে সংজ্ঞায়িত ম্যাক্রো ব্যবহার করি:

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

ইচ্ছাকৃত আকারের বিটম্যাপগুলির জন্য আরো সাধারণ:

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

এই হিসাবে "এমবেডেড" ট্যাগ করা হয় আমি অনুমান করব আপনি একটি মাইক্রোকন্ট্রোলার ব্যবহার করছেন। উপরের সমস্ত পরামর্শ বৈধ এবং কাজ (পড়া-সংশোধন-লিখুন, ইউনিয়ন, structs, ইত্যাদি)।

যাইহোক, অসিওলোস্কোপ-ভিত্তিক ডিবাগিংয়ের সময় আমি জানতে পেরেছিলাম যে এই পদ্ধতিগুলি মাইক্রো এর পোর্টএনএসইটি / পোর্টএনসিএলএআরএআরআর নিবন্ধকদের কাছে সরাসরি মান লেখার তুলনায় CPU চক্রগুলির মধ্যে একটি উল্লেখযোগ্য ওভারহেড আছে যা একটি প্রকৃত পার্থক্য তৈরি করে যেখানে টাইট loops / high ফ্রিকোয়েন্সি আইএসআর এর টগলিং পিন।

অপরিচিতদের জন্য: আমার উদাহরণে, মাইক্রোটিতে একটি সাধারণ পিন-স্টেট নিবন্ধন পোর্ট্ন রয়েছে যা আউটপুট পিনগুলিকে প্রতিফলিত করে, তাই PORTN | = BIT_TO_SET করে সেটি রিজার্ভ করার জন্য একটি পঠন-সংশোধন-লেখায় ফলাফল করে। যাইহোক, PORTNSET / PORTNCLEAR নিবন্ধকগুলি "1 টি" এটিকে "1 বিট করুন" (SET) বা "দয়া করে এই বিট জিরো করুন" (স্বচ্ছ) এবং একটি '0' মানে "পিন একা ছেড়ে দিন" এর অর্থ নিতে পারে। সুতরাং, আপনি বিট সেটিং করা বা সাফ করা (সবসময় সুবিধাজনক নয়) তবে একটি খুব দ্রুত প্রতিক্রিয়া এবং ছোট একত্রিত কোডের উপর নির্ভর করে আপনি দুটি পোর্ট ঠিকানা শেষ করেছেন।


এখানে আমার পছন্দের বিট গাণিতিক ম্যাক্রো, যা size_t 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, &)) ...

প্রভৃতি


এটি কখনও কখনও বিট নামে একটি enum ব্যবহার করে মূল্যবান:

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

তারপর পরে নাম ব্যবহার করুন। আমি লিখি

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

সেট, পরিষ্কার এবং পরীক্ষা। এই ভাবে আপনি আপনার বাকি কোড থেকে যাদু সংখ্যা লুকান।

অন্যথায় আমি জেরেমি এর সমাধান সমর্থন করি।


বিটwise অপারেটরগুলি ব্যবহার করুন: & |

000b মধ্যে শেষ বিট সেট করতে:

foo = foo | 001b

foo মধ্যে শেষ বিট চেক করার জন্য:

if ( foo & 001b ) ....

foo মধ্যে শেষ বিট সাফ করুন:

foo = foo & 110b

আমি স্বচ্ছতার জন্য XXXb ব্যবহার। আপনি সম্ভবত প্যাকিং বিটগুলির মধ্যে ডেটা স্ট্রাকচারের উপর নির্ভর করে, হ্যাক উপস্থাপনাটির সাথে কাজ করবেন।


শিক্ষার জন্য আমি একটি উদাহরণ দিয়ে আরো কিছু ব্যাখ্যা করতে চাই:

উদাহরণ:

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)

স্ট্যান্ডার্ড সি ++ লাইব্রেরি ব্যবহার করে: std::bitset<N>

বা Boost সংস্করণ: 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

বুস্ট সংস্করণটি একটি স্ট্যান্ডার্ড লাইব্রেরী কম্পাইল-সময় আকারের বিটসেটের তুলনায় রানটাইম আকারের বিটসেটকে মঞ্জুরি দেয়।


একটি C ++ 11 templated সংস্করণ (একটি শিরোনাম মধ্যে রাখা):

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

পরিবর্তনশীল ব্যবহৃত

int value, pos;

মান - ডেটা
pos - আমরা সেট করতে আগ্রহী বিট অবস্থান, স্পষ্ট বা টগল
একটি বিট সেট

value = value | 1 << pos;

একটু সাফ করুন

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

একটি বিট টগল করুন

value = value ^ 1 << pos;

সি বিট পরিবর্তন করার জন্য এই ভাষাগুলির মধ্যে একটি ফাংশনটি চেষ্টা করুন:

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

here সংজ্ঞায়িত হিসাবে অপারেটর এক ব্যবহার here

একটি বিট সেট, বাইনারি ফর্ম বিট অবস্থান int x = x | 0x?;যেখানে ব্যবহৃত ?হয়।


যদি আপনি লিনাক্স কার্নেলের সি প্রোগ্রামিংয়ের সাথে এই সমস্ত ক্রিয়াকলাপটি সঞ্চালন করতে চান তবে আমি Linux কার্নেলের স্ট্যান্ডার্ড API ব্যবহার করার পরামর্শ দিই।

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