Pertanyaan Bagaimana Anda mengatur, menghapus, dan beralih sedikit?


Bagaimana Anda mengatur, menghapus, dan mengaktifkan sedikit di C / C + +?


2048
2017-09-07 00:42


asal


Jawaban:


Pengaturan sedikit

Gunakan operator OR bitwise (|) untuk mengatur sedikit.

number |= 1UL << n;

Itu akan mengatur nsedikit number.

Menggunakan 1ULL jika number lebih lebar dari unsigned long; promosi 1UL << n tidak terjadi sampai setelah mengevaluasi 1UL << n di mana perilaku tidak terdefinisi untuk bergeser lebih dari lebar a long. Hal yang sama berlaku untuk semua sisa contoh.

Membersihkan sedikit

Gunakan operator DAN bitwise (&) untuk membersihkan sedikit.

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

Itu akan menghapus nsedikit number. Anda harus membalikkan bit string dengan operator bitwise NOT (~), lalu DAN itu.

Beralih sedikit

Operator XOR (^) dapat digunakan untuk beralih sedikit.

number ^= 1UL << n;

Itu akan beralih nsedikit number.

Memeriksa sedikit

Anda tidak meminta ini, tapi saya mungkin juga menambahkannya.

Untuk memeriksa sedikit, geser nomor n ke kanan, lalu bitwise DAN itu:

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

Itu akan menempatkan nilai dari nsedikit number ke dalam variabel bit.

Mengubah nsedikit ke x

Pengaturan nsedikit juga 1 atau 0 dapat dicapai dengan yang berikut pada implementasi C ++ komplemen 2:

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

Sedikit n akan diatur jika x aku s 1, dan dibersihkan jika x aku s 0. Jika x memiliki beberapa nilai lain, Anda mendapatkan sampah. x = !!x akan booleanize ke 0 atau 1.

Untuk membuat ini independen dari perilaku negasi komplementasi 2 (di mana -1 memiliki semua bit set, tidak seperti pada pelengkap 1 atau tanda / besarnya C + + implementasi), gunakan negasi unsigned.

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

atau

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

Ini biasanya ide yang baik untuk menggunakan tipe unsigned untuk manipulasi bit portabel.

Itu juga umumnya ide yang baik untuk tidak menyalin / menyisipkan kode pada umumnya dan begitu banyak orang menggunakan makro preprocessor (seperti komunitas wiki menjawab lebih jauh) atau semacam enkapsulasi.


2997
2017-09-07 00:50



Menggunakan Standar C ++ Library: std::bitset<N>.

Atau itu Dorongan versi: boost::dynamic_bitset.

Tidak perlu menggulung Anda sendiri:

#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

Versi Boost memungkinkan bitet ukuran runtime dibandingkan dengan perpustakaan standar bitet waktu kompilasi.


381
2017-09-18 00:34



Pilihan lainnya adalah menggunakan bidang bit:

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

struct bits mybits;

mendefinisikan bidang 3-bit (sebenarnya, itu tiga felds 1-bit). Operasi bit sekarang menjadi sedikit (haha) lebih sederhana:

Untuk mengatur atau menghapus sedikit:

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

Untuk beralih sedikit:

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

Memeriksa sedikit:

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

Ini hanya berfungsi dengan bidang bit ukuran tetap. Kalau tidak, Anda harus menggunakan teknik bit-twiddling yang dijelaskan dalam posting sebelumnya.


212
2017-09-11 00:56



Saya menggunakan makro yang didefinisikan dalam file header untuk menangani set bit dan jelas:

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



Terkadang layak menggunakan enum untuk nama bit-bit:

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

Kemudian gunakan nama-nama kemudian. Yaitu. menulis

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

untuk mengatur, membersihkan dan menguji. Dengan cara ini Anda menyembunyikan angka ajaib dari sisa kode Anda.

Selain itu saya mendukung solusi Jeremy.


99
2017-09-17 02:04



Dari snip-c.zipbitops.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)))

Oke, mari kita menganalisis hal-hal ...

Ekspresi umum yang Anda tampaknya mengalami masalah dengan semua ini adalah "(1L << (posn))". Semua ini adalah membuat topeng dengan bit tunggal dan yang akan bekerja dengan tipe integer apa pun. Argumen "posn" menentukan posisi di mana Anda ingin sedikit. Jika posn == 0, maka ekspresi ini akan mengevaluasi ke:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

Jika posn == 8, itu akan dievaluasi

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

Dengan kata lain, itu hanya menciptakan bidang 0 dengan 1 pada yang ditentukan posisi. Satu-satunya bagian yang sulit adalah di BitClr () makro di mana kita perlu mengatur satu bit 0 dalam bidang 1. Ini dilakukan dengan menggunakan 1 itu melengkapi ekspresi yang sama dengan dilambangkan dengan operator tilde (~).

Setelah topeng dibuat, itu diterapkan ke argumen seperti yang Anda sarankan, dengan menggunakan operator bitwise dan (&), atau (|), dan xor (^). Sejak topeng adalah tipe panjang, macro akan bekerja sama seperti pada char, short, int, atau panjang.

Intinya adalah bahwa ini adalah solusi umum untuk seluruh kelas masalah. Ini, tentu saja, mungkin dan bahkan tepat untuk menulis ulang setara dengan salah satu makro ini dengan nilai mask eksplisit setiap kali Anda butuh satu, tapi mengapa melakukannya? Ingat, substitusi makro terjadi di preprocessor dan kode yang dihasilkan akan mencerminkan fakta bahwa nilai-nilai dianggap konstan oleh kompilator - itu sama efisien untuk digunakan makro umum untuk "menemukan kembali roda" setiap kali Anda perlu melakukannya sedikit manipulasi.

Tidak yakin? Berikut ini beberapa kode pengujian - Saya menggunakan Watcom C dengan optimalisasi penuh dan tanpa menggunakan _cdecl sehingga pembongkaran yang dihasilkan akan sebersih mungkin:

---- [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 (disassembled)] -------------------------------------- ---------

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



Untuk pemula saya ingin menjelaskan sedikit lebih banyak dengan sebuah contoh:

Contoh:

value is 0x55;
bitnum : 3rd.

Itu & operator digunakan memeriksa 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 atau Flip:

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

| operator: atur sedikit

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

28
2017-09-07 00:45



Gunakan operator bitwise: &  | 

Untuk mengatur bit terakhir 000b:

foo = foo | 001b

Untuk memeriksa bit terakhir di foo:

if ( foo & 001b ) ....

Untuk menghapus bit terakhir di foo:

foo = foo & 110b

Saya menggunakan XXXb untuk kejelasan. Anda mungkin akan bekerja dengan representasi HEX, tergantung pada struktur data di mana Anda mengepak bit.


26
2017-07-13 06:53



Ini adalah makro aritmatika bit favorit saya, yang berfungsi untuk semua jenis bilangan bulat unsigned unsigned char hingga size_t (yang merupakan jenis terbesar yang harus efisien untuk dikerjakan):

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

Untuk mengatur sedikit:

BITOP(array, bit, |=);

Untuk menghapus sedikit:

BITOP(array, bit, &=~);

Untuk beralih sedikit:

BITOP(array, bit, ^=);

Untuk menguji sedikit:

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

dll.


24
2018-06-14 15:23



Karena ini ditandai "tertanam" saya akan berasumsi Anda menggunakan mikrokontroler. Semua saran di atas valid & berfungsi (baca-ubah-tulis, serikat, struct, dll.).

Namun, selama serangan debug berbasis oscilloscope saya kagum untuk menemukan bahwa metode ini memiliki overhead yang cukup besar dalam siklus CPU dibandingkan dengan menulis nilai langsung ke pORTnSET / PORTnCLEAR register mikro yang membuat perbedaan nyata di mana ada loop ketat / tinggi -fungsi pin toggling ISR.

Bagi mereka yang tidak dikenal: Dalam contoh saya, mikro memiliki pin-state register PORTn umum yang mencerminkan pin output, sehingga melakukan PORTn | = BIT_TO_SET menghasilkan read-modify-write ke register itu. Namun, daftar PORTNSET / PORTnCLEAR mengambil '1' berarti "tolong buat ini sedikit 1" (SET) atau "tolong buat ini sedikit nol" (CLEAR) dan '0' berarti "biarkan pin saja". jadi, Anda berakhir dengan dua alamat port tergantung apakah Anda sedang mengatur atau membersihkan bit (tidak selalu nyaman) tetapi a banyak reaksi lebih cepat dan kode rakitan yang lebih kecil.


22
2017-11-06 11:30



Pendekatan bitfield memiliki kelebihan lain di arena tertanam. Anda dapat menentukan struct yang memetakan langsung ke bit di register perangkat keras tertentu.

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;

Anda perlu menyadari urutan pengemasan sedikit - saya pikir itu MSB pertama, tapi ini mungkin tergantung pada implementasi. Juga, verifikasi bagaimana bidang penangan compiler Anda melintasi batas byte.

Anda kemudian dapat membaca, menulis, menguji nilai-nilai individu seperti sebelumnya.


20
2018-06-13 21:27