Bagaimana Anda mengatur, menghapus, dan beralih sedikit pun?

Jawaban:

3600

Pengaturan sedikit

Gunakan bitwise OR operator ( |) untuk mengatur bit.

number |= 1UL << n;

Itu akan mengatur nbit th number. nharus nol, jika Anda ingin mengatur 1bit st dan seterusnya n-1, jika Anda ingin mengatur nbit th.

Gunakan 1ULLjika numberlebih luas dari unsigned long; promosi 1UL << ntidak terjadi sampai setelah mengevaluasi di 1UL << nmana perilaku yang tidak ditentukan untuk bergeser lebih dari lebar a long. Hal yang sama berlaku untuk semua contoh lainnya.

Bersihkan sedikit

Gunakan bitwise AND operator ( &) untuk menghapus sedikit.

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

Itu akan menghapus nsedikit number. Anda harus membalikkan string bit dengan operator NOT bitwise ( ~), 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, tetapi saya mungkin juga menambahkannya.

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

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

Itu akan menempatkan nilai nbit numberke dalam variabel bit.

Mengubah n th bit untuk x

Mengatur nbit th ke salah satu 1atau 0dapat dicapai dengan yang berikut pada implementasi C ++ 2 komplemen:

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

Bit nakan ditetapkan jika xini 1, dan dibersihkan jika xini 0. Jika xmemiliki nilai lain, Anda mendapatkan sampah. x = !!xakan mendudukkannya menjadi 0 atau 1.

Untuk menjadikan ini tidak tergantung pada perilaku negasi komplemen 2 (di mana -1semua bit diatur, tidak seperti pada komplemen 1 atau implementasi sign / magnitude C ++), gunakan negasi yang tidak ditandatangani.

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 umumnya ide yang baik untuk menggunakan tipe yang tidak ditandatangani untuk manipulasi bit portabel.

atau

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

(number & ~(1UL << n))akan menghapus nbit th dan (x << n)akan mengatur nbit th ke x.

Ini juga umumnya ide yang baik untuk tidak menyalin / menempel kode secara umum dan begitu banyak orang menggunakan macro preprocessor (seperti komunitas wiki menjawab lebih jauh ke bawah ) atau semacam enkapsulasi.

Jeremy Ruten
sumber
128
Saya ingin mencatat bahwa pada platform yang memiliki dukungan asli untuk bit set / clear (ex, AVR mikrokontroler), kompiler akan sering menerjemahkan 'myByte | = (1 << x)' ke dalam set bit asli / instruksi yang jelas setiap kali x adalah konstanta, ex: (1 << 5), atau const unsigned x = 5.
Aaron
52
bit = number & (1 << x); tidak akan memasukkan nilai bit x ke dalam bit kecuali bit memiliki tipe _Bool (<stdbool.h>). Jika tidak, bit = !! (angka & (1 << x)); akan ..
Chris Young
23
mengapa Anda tidak mengubah yang terakhir kebit = (number >> x) & 1
aaronman
42
1adalah intliteral, yang ditandatangani. Jadi semua operasi di sini beroperasi pada angka yang ditandatangani, yang tidak didefinisikan dengan baik oleh standar. Standar tidak menjamin komplemen dua atau pergeseran aritmatika sehingga lebih baik digunakan 1U.
Siyuan Ren
50
Saya lebih suka number = number & ~(1 << n) | (x << n);untuk Mengubah bit ke-x ke x.
jiasli
459

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

Atau Meningkatkan versi: boost::dynamic_bitset.

Tidak perlu menggulung 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 berukuran runtime dibandingkan dengan bitet berukuran waktu kompilasi pustaka standar .

Martin York
sumber
34
+1. Bukan berarti std :: bitset dapat digunakan dari "C", tetapi ketika penulis menandai pertanyaannya dengan "C ++", AFAIK, jawaban Anda adalah yang terbaik di sini ... std :: vector <bool> adalah cara lain, jika ada yang tahu pro dan kontra
paercebal
23
@andrewdotnich: vector <bool> adalah (sayangnya) spesialisasi yang menyimpan nilai sebagai bit. Lihat gotw.ca/publications/mill09.htm untuk info lebih lanjut ...
Niklas
71
Mungkin tidak ada yang menyebutkannya karena ini ditandai dengan tag. Dalam kebanyakan sistem embedded, Anda menghindari STL seperti wabah. Dan meningkatkan dukungan kemungkinan adalah burung yang sangat langka untuk dikenali di antara kebanyakan kompiler yang tertanam.
Lundin
17
@ Martin Ini sangat benar. Selain pembunuh kinerja spesifik seperti STL dan templat, banyak sistem yang disematkan bahkan menghindari seluruh pustaka standar sepenuhnya, karena mereka sulit untuk diverifikasi. Sebagian besar cabang tertanam menggunakan standar seperti MISRA, yang memerlukan alat analisis kode statis (setiap profesional perangkat lunak harus menggunakan alat seperti itu, bukan hanya orang yang disematkan). Umumnya orang memiliki hal-hal yang lebih baik untuk dilakukan daripada menjalankan analisis statis melalui seluruh perpustakaan standar - jika kode sumbernya bahkan tersedia untuk mereka di kompiler tertentu.
Lundin
37
@Lundin: Pernyataan Anda terlalu luas (sehingga tidak berguna untuk berdebat tentang). Saya yakin bahwa saya dapat menemukan situasi jika itu benar. Ini tidak mengubah titik awal saya. Kedua kelas ini baik-baik saja untuk digunakan dalam sistem embedded (dan saya tahu pasti bahwa mereka digunakan). Poin awal Anda tentang STL / Boost yang tidak digunakan pada sistem embedded juga salah. Saya yakin ada sistem yang tidak menggunakannya dan bahkan sistem yang menggunakannya mereka digunakan dengan bijak tetapi mengatakan mereka tidak digunakan sama sekali tidak benar (karena ada sistem mereka digunakan).
Martin York
248

Opsi 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 bidang 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 bekerja dengan bidang bit ukuran tetap. Kalau tidak, Anda harus menggunakan teknik bit-twiddling yang dijelaskan dalam posting sebelumnya.

Ferruccio
sumber
68
Saya selalu menemukan menggunakan bitfield adalah ide yang buruk. Anda tidak memiliki kendali atas urutan alokasi bit (dari atas atau bawah), yang membuatnya tidak mungkin untuk membuat serialisasi nilai dengan cara yang stabil / portabel kecuali bit-at-a-time. Juga tidak mungkin untuk mencampur bit aritmatika DIY dengan bitfield, misalnya membuat topeng yang menguji beberapa bit sekaligus. Anda tentu saja dapat menggunakan && dan berharap kompiler akan mengoptimalkannya dengan benar ...
R .. GitHub STOP BANTUAN ICE
34
Bidang bit buruk dalam banyak hal, saya hampir bisa menulis buku tentang itu. Bahkan saya hampir harus melakukan itu untuk program lapangan sedikit yang membutuhkan kepatuhan MISRA-C. MISRA-C memberlakukan semua perilaku yang ditentukan implementasi untuk didokumentasikan, jadi saya akhirnya menulis esai tentang segala sesuatu yang bisa salah dalam bidang bit. Urutan bit, endianess, padding bit, padding byte, berbagai masalah penyelarasan lainnya, konversi tipe implisit dan eksplisit ke dan dari bidang bit, UB jika int tidak digunakan dan sebagainya. Sebagai gantinya, gunakan operator bitwise untuk mengurangi bug dan kode portabel. Bidang bit sepenuhnya berlebihan.
Lundin
44
Seperti kebanyakan fitur bahasa, bidang bit dapat digunakan dengan benar atau disalahgunakan. Jika Anda perlu mengemas beberapa nilai kecil ke dalam int tunggal, bidang bit bisa sangat berguna. Di sisi lain, jika Anda mulai membuat asumsi tentang bagaimana bidang bit memetakan ke int yang sebenarnya berisi, Anda hanya meminta masalah.
Ferruccio
4
@endolith: Itu bukan ide yang bagus. Anda bisa membuatnya bekerja, tetapi itu tidak harus portabel untuk prosesor yang berbeda, atau ke kompiler yang berbeda atau bahkan untuk rilis berikutnya dari kompiler yang sama.
Ferruccio
3
@Yasky dan Ferruccio mendapatkan jawaban berbeda untuk sizeof () untuk pendekatan ini harus menggambarkan masalah dengan kompatibilitas tidak hanya di seluruh kompiler tetapi di seluruh perangkat keras. Kami kadang-kadang menipu diri sendiri bahwa kami telah memecahkan masalah ini dengan bahasa atau runtimes yang ditentukan tetapi benar-benar turun ke 'akankah ini bekerja pada mesin saya?'. Kalian orang-orang yang tertanam sangat menghargai saya (dan simpati).
Kelly S. French
181

Saya menggunakan makro yang didefinisikan dalam file header untuk menangani bit yang diatur dan dihapus:

/* 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))
Steve Karg
sumber
17
Eh saya sadar ini posting lama 5 tahun tapi tidak ada duplikasi argumen di salah satu makro itu, Dan
Robert Kelly
11
BITMASK_CHECK(x,y) ((x) & (y))harus ((x) & (y)) == (y)dinyatakan sebaliknya mengembalikan hasil yang salah pada multibit mask (mis. 5vs. 3) / * Halo untuk semua penggali kubur
:)
7
1harus (uintmax_t)1serupa atau seandainya ada yang mencoba menggunakan makro ini pada longtipe yang lebih besar
MM
2
BITMASK_CHECK_ALL(x,y)dapat diimplementasikan sebagai!~((~(y))|(x))
Handy999
3
@ Handy999 Agak lebih mudah untuk melihat mengapa itu bekerja setelah menerapkan hukum De Morgan dan mengatur ulang untuk mendapatkan!(~(x) & (y))
Tavian Barnes
114

Kadang-kadang layak digunakan enumuntuk menamai bit:

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

Kemudian gunakan nama nanti. Yaitu menulis

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

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

Selain itu saya mendukung solusi Jeremy.

dmckee --- mantan kucing moderator
sumber
1
Bergantian Anda bisa membuat clearbits()fungsi, bukan &= ~. Mengapa Anda menggunakan enum untuk ini? Saya pikir itu untuk membuat banyak variabel unik dengan nilai arbitrase tersembunyi, tetapi Anda menetapkan nilai yang pasti untuk masing-masing. Jadi apa untungnya vs mendefinisikan mereka sebagai variabel?
endolith
4
@endolith: Penggunaan enums untuk set konstanta terkait kembali pada pemrograman c. Saya menduga bahwa dengan kompiler modern satu-satunya keuntungan di atas const shortatau apa pun adalah bahwa mereka secara eksplisit dikelompokkan bersama. Dan ketika Anda ingin mereka untuk sesuatu yang lain daripada bitmasks Anda mendapatkan penomoran otomatis. Dalam c ++ tentu saja, mereka juga membentuk tipe berbeda yang memberi Anda sedikit tambahan pengecekan kesalahan statis.
dmckee --- ex-moderator kitten
Anda akan masuk ke dalam konstanta enum yang tidak terdefinisi jika Anda tidak mendefinisikan konstanta untuk masing-masing nilai bit yang mungkin. Apa enum ThingFlagsgunanya ThingError|ThingFlag1, misalnya?
Luis Colorado
6
Jika Anda menggunakan metode ini, harap diingat bahwa konstanta enum selalu bertanda tangan int. Ini dapat menyebabkan segala macam bug halus karena promosi integer implisit atau operasi bitwise pada tipe yang ditandatangani. thingstate = ThingFlag1 >> 1misalnya akan meminta perilaku yang ditentukan implementasi. thingstate = (ThingFlag1 >> x) << ydapat memanggil perilaku yang tidak terdefinisi. Dan seterusnya. Agar aman, selalu dilemparkan ke jenis yang tidak ditandatangani.
Lundin
1
@Lundin: Pada C ++ 11, Anda dapat mengatur tipe enumerasi yang mendasarinya, misalnya: enum My16Bits: unsigned short { ... };
Aiken Drum
47

Dari bitip.h snip-c.zip:

/*
**  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 tampaknya Anda mengalami masalah dengan semua ini adalah "(1L << (posn))". Semua ini dilakukan adalah membuat topeng dengan bit tunggal dan yang akan bekerja dengan semua tipe integer. Argumen "posn" menentukan posisi di mana Anda menginginkan bit. Jika posn == 0, maka ungkapan ini akan mengevaluasi ke:

0000 0000 0000 0000 0000 0000 0000 0001 binary.

Jika posn == 8, itu akan mengevaluasi ke:

0000 0000 0000 0000 0000 0001 0000 0000 binary.

Dengan kata lain, itu hanya membuat bidang 0 dengan 1 pada posisi yang ditentukan. Satu-satunya bagian yang sulit adalah dalam makro BitClr () di mana kita perlu mengatur 0 bit tunggal dalam bidang 1 ini. Ini dicapai dengan menggunakan komplemen 1 dari ekspresi yang sama seperti dilambangkan oleh operator tilde (~).

Setelah mask dibuat, itu diterapkan pada argumen seperti yang Anda sarankan, dengan menggunakan bitwise dan (&), atau (|), dan xor (^) operator. Karena topeng bertipe panjang, makro akan bekerja dengan baik pada karakter char, short, int, atau long.

Intinya adalah bahwa ini adalah solusi umum untuk seluruh kelas masalah. Tentu saja mungkin dan bahkan pantas untuk menulis ulang ekuivalen dari makro ini dengan nilai mask eksplisit setiap kali Anda membutuhkannya, tetapi mengapa melakukannya? Ingat, substitusi makro terjadi di preprocessor dan kode yang dihasilkan akan mencerminkan fakta bahwa nilai-nilai dianggap konstan oleh kompiler - yaitu sama efisiennya dengan menggunakan makro umum untuk "menciptakan kembali roda" setiap kali Anda perlu melakukan manipulasi bit.

Tidak yakin? Berikut ini beberapa kode uji - Saya menggunakan Watcom C dengan optimisasi 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 (dibongkar)] -------------------------------------- ---------

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

yogeesh
sumber
3
2 hal tentang ini: (1) dalam membaca makro Anda, beberapa mungkin salah percaya bahwa makro benar-benar mengatur / menghapus / membalik bit dalam argumen, namun tidak ada tugas; (2) test.c Anda tidak lengkap; Saya menduga jika Anda menjalankan lebih banyak kasus, Anda akan menemukan masalah (latihan pembaca)
Dan
19
-1 Ini hanya kebingungan aneh. Jangan pernah menemukan kembali bahasa C dengan menyembunyikan sintaks bahasa di balik makro, itu adalah praktik yang sangat buruk. Kemudian beberapa keanehan: pertama, 1L ditandatangani, artinya semua operasi bit akan dilakukan pada tipe yang ditandatangani. Segala sesuatu yang diteruskan ke makro ini akan kembali seperti yang ditandatangani lama. Tidak baik. Kedua, ini akan bekerja sangat tidak efisien pada CPU yang lebih kecil karena ini akan berlaku lama ketika operasi bisa berada di level int. Ketiga, makro seperti fungsi adalah akar dari semua kejahatan: Anda tidak memiliki tipe keamanan apa pun. Juga, komentar sebelumnya tentang tidak ada tugas sangat valid.
Lundin
2
Ini akan gagal jika argada long long. 1Lperlu jenis seluas mungkin, jadi (uintmax_t)1. (Anda mungkin lolos 1ull)
MM
Apakah Anda mengoptimalkan ukuran kode? Pada Intel mainstream CPU Anda akan mendapatkan warung register sebagian saat membaca AX atau EAX setelah fungsi ini kembali, karena ia menulis komponen 8-bit EAX. (Tidak masalah pada CPU AMD, atau yang lain yang tidak mengubah nama register parsial secara terpisah dari register lengkap. Haswell / Skylake tidak mengganti nama AL secara terpisah, tetapi mereka mengganti nama AH. ).
Peter Cordes
37

Gunakan operator bitwise: & |

Untuk mengatur bit terakhir di 000b:

foo = foo | 001b

Untuk memeriksa bit terakhir di foo:

if ( foo & 001b ) ....

Untuk menghapus bit terakhir di foo:

foo = foo & 110b

Saya menggunakan XXXbuntuk kejelasan. Anda mungkin akan bekerja dengan representasi HEX, tergantung pada struktur data tempat Anda mengemas bit.

nsanders
sumber
7
Tidak ada notasi biner dalam C. Konstanta integer biner adalah ekstensi non-standar.
Lundin
Gunakan XOR untuk beralih sedikit:foo = foo ^ MY_MASK
Peter L
Gunakan BUKAN untuk membalikkan topeng untuk membersihkan:foo = foo & ~MY_MASK
Peter L
32

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

Contoh:

value is 0x55;
bitnum : 3rd.

The &operator yang 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)

Beralih atau Balik:

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

| operator: atur bitnya

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

Inilah makro aritmatika bit favorit saya, yang berfungsi untuk semua jenis bilangan bulat tak bertanda dari unsigned charhingga size_t(yang merupakan jenis terbesar yang harus efisien untuk bekerja dengannya):

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

R .. GitHub BERHENTI MEMBANTU ES
sumber
5
Ini bagus untuk dibaca tetapi orang harus menyadari kemungkinan efek sampingnya. Menggunakan BITOP(array, bit++, |=);dalam satu lingkaran kemungkinan besar tidak akan melakukan apa yang diinginkan pemanggil.
foraidt
Memang. =) Satu varian yang mungkin Anda sukai adalah untuk memisahkannya menjadi 2 makro, 1 untuk mengatasi elemen array dan yang lain untuk menggeser bit ke tempatnya, ala BITCELL(a,b) |= BITMASK(a,b);(keduanya mengambil asebagai argumen untuk menentukan ukuran, tetapi yang terakhir tidak akan pernah mengevaluasi akarena hanya muncul di sizeof).
R .. GitHub BERHENTI MEMBANTU ICE
1
@ R .. Jawaban ini benar-benar tua, tapi saya mungkin lebih suka fungsi daripada makro dalam kasus ini.
PC Luddite
Kecil: 3 (size_t)pemain tampaknya berada di sana hanya untuk memastikan beberapa matematika unsigned dengan %. Bisa di (unsigned)sana
chux - Reinstate Monica
Yang (size_t)(b)/(8*sizeof *(a))tidak perlu bisa menyempit bsebelum divisi. Hanya masalah dengan bit array yang sangat besar. Masih makro yang menarik.
chux - Reinstate Monica
25

Karena ini ditandai "tertanam" Saya akan menganggap Anda menggunakan mikrokontroler. Semua saran di atas adalah valid & berfungsi (baca-modifikasi-tulis, serikat pekerja, struct, dll.).

Namun, selama serangan debugging berbasis osiloskop saya kagum menemukan bahwa metode ini memiliki overhead yang cukup besar dalam siklus CPU dibandingkan dengan menulis nilai langsung ke register PORTnSET / PORTnCLEAR mikro yang membuat perbedaan nyata di mana ada loop ketat / tinggi Pin pengalih frekuensi ISR.

Bagi mereka yang tidak terbiasa: Dalam contoh saya, mikro memiliki register umum pin-state PORTn yang mencerminkan pin keluaran, sehingga melakukan PORTn | = BIT_TO_SET menghasilkan baca-modifikasi-tulis ke register itu. Namun, register PORTnSET / PORTnCLEAR mengambil '1' yang berarti "tolong buat bit ini 1" (SET) atau "tolong buat bit ini nol" (CLEAR) dan tanda '0' berarti "biarkan pin sendirian". jadi, Anda berakhir dengan dua alamat port tergantung apakah Anda mengatur atau menghapus bit (tidak selalu nyaman) tetapi reaksi yang jauh lebih cepat dan kode rakitan yang lebih kecil.

John U
sumber
Micro adalah Coldfire MCF52259, menggunakan C di Codewarrior. Melihat disassembler / asm adalah latihan yang berguna karena menunjukkan semua langkah yang harus dilalui CPU untuk melakukan bahkan operasi yang paling dasar. <br> Kami juga melihat instruksi pemogokan CPU lainnya dalam waktu-kritis - membatasi variabel dengan melakukan var% = max_val biaya setumpuk siklus CPU setiap kali, sementara melakukan jika (var> max_val) var- = max_val hanya menggunakan beberapa instruksi. <br> Panduan yang bagus untuk beberapa trik lagi ada di sini: codeproject.com/Articles/6154/…
John U
Yang lebih penting lagi, register I / O yang dipetakan dengan memori pembantu menyediakan mekanisme untuk pembaruan atom. Baca / modifikasi / tulis bisa sangat buruk jika urutannya terputus.
Ben Voigt
1
Perlu diingat bahwa semua register port akan didefinisikan sebagai volatiledan karena itu kompiler tidak dapat melakukan optimasi pada kode yang melibatkan register tersebut. Oleh karena itu, praktik yang baik untuk membongkar kode tersebut dan melihat bagaimana hasilnya pada tingkat assembler.
Lundin
24

Pendekatan bitfield memiliki kelebihan lain di arena tertanam. Anda dapat mendefinisikan struct yang memetakan langsung ke bit dalam 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 harus mengetahui urutan pengepakan bit - Saya pikir ini MSB pertama, tetapi ini mungkin tergantung pada implementasi. Juga, verifikasi bagaimana kompiler Anda menangani bidang melintasi batas byte.

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

Roddy
sumber
2
Cukup banyak segala sesuatu tentang bidang bit yang ditentukan implementasi. Bahkan jika Anda berhasil menemukan semua detail tentang bagaimana kompiler khusus Anda mengimplementasikannya, menggunakannya dalam kode Anda pasti akan membuatnya non-portabel.
Lundin
1
@Lundin - Benar, tetapi sistem sedikit-mengutak-atik (terutama di register perangkat keras, yang merupakan jawaban saya berhubungan dengan) tidak akan pernah berguna portabel.
Roddy
1
Mungkin bukan di antara CPU yang sepenuhnya berbeda. Tetapi Anda kemungkinan besar ingin itu portabel antara kompiler dan antara proyek yang berbeda. Dan ada banyak "fiddling" tertanam yang tidak berhubungan dengan perangkat keras sama sekali, seperti pengkodean / decoding data protokol.
Lundin
... dan jika Anda terbiasa menggunakan bidang bit melakukan pemrograman tertanam, Anda akan menemukan kode X86 Anda berjalan lebih cepat, dan lebih ramping juga. Bukan dalam tolok ukur sederhana di mana Anda memiliki seluruh alat berat untuk menghancurkan patokan, tetapi di lingkungan multi-tasking dunia nyata di mana program bersaing untuk sumber daya. Advantage CISC - yang tujuan desain awalnya adalah mengganti CPU lebih cepat dari bus dan memperlambat memori.
20

Periksa sedikit di lokasi sewenang-wenang dalam variabel tipe sewenang-wenang:

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

Penggunaan sampel:

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

Catatan: Ini dirancang agar cepat (mengingat fleksibilitasnya) dan tidak bercabang. Ini menghasilkan kode mesin SPARC yang efisien saat dikompilasi Sun Studio 8; Saya juga sudah mengujinya menggunakan MSVC ++ 2008 pada amd64. Dimungkinkan untuk membuat makro yang sama untuk pengaturan dan menghapus bit. Perbedaan utama dari solusi ini dibandingkan dengan banyak yang lain di sini adalah bahwa ia berfungsi untuk semua lokasi di hampir semua jenis variabel.

John Zwinck
sumber
20

Lebih umum, untuk bitmap berukuran acak:

#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)))
tagihan
sumber
2
CHAR_BITsudah ditentukan oleh limits.h, Anda tidak perlu memasukkannya sendiri BITS(dan faktanya membuat kode Anda lebih buruk dengan melakukannya)
MM
14

Program ini untuk mengubah bit data apa saja dari 0 menjadi 1 atau 1 menjadi 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);
        }
    }
}
Gokul Naathan
sumber
14

Jika Anda melakukan banyak twiddling, Anda mungkin ingin menggunakan masker yang akan membuat semuanya lebih cepat. Fungsi-fungsi berikut sangat cepat dan masih fleksibel (mereka memungkinkan sedikit memutar-mutar peta bit dari berbagai ukuran).

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

Catatan, untuk mengatur bit 'n' dalam bilangan bulat 16 bit Anda melakukan hal berikut:

TSetBit( n, &my_int);

Terserah Anda untuk memastikan bahwa nomor bit berada dalam kisaran peta bit yang Anda lewati. Perhatikan bahwa untuk prosesor endian kecil yang byte, kata-kata, kata-kata, kata-kata, dll., Memetakan dengan benar satu sama lain dalam memori (alasan utama bahwa prosesor endian kecil 'lebih baik' dari prosesor big-endian, ah, saya merasakan perang api datang di...).

Tim Ring
sumber
2
Jangan gunakan tabel untuk fungsi yang dapat diimplementasikan dengan satu operator. TQuickByteMask [n] setara dengan (1 << n). Juga, membuat argumen Anda singkat adalah ide yang sangat buruk. The / dan% akan benar-benar menjadi pembagian, bukan bithift / bitwise dan, karena pembagian yang ditandatangani dengan kekuatan 2 tidak dapat diimplementasikan bitwise. Anda harus membuat tipe argumen unsigned int!
R .. GitHub BERHENTI MEMBANTU ICE
Apa gunanya ini? Itu hanya membuat kode lebih lambat dan lebih sulit untuk dibaca? Saya tidak bisa melihat satu keuntungan pun dari itu. 1u << n lebih mudah dibaca untuk programmer C, dan mudah-mudahan dapat diterjemahkan ke dalam instruksi clock tick CPU tunggal. Divisi Anda di sisi lain, akan diterjemahkan ke sesuatu sekitar 10 kutu, atau bahkan seburuk hingga 100 kutu, tergantung pada seberapa buruk arsitektur spesifik menangani divisi. Adapun fitur bitmap, akan lebih masuk akal untuk memiliki tabel pencarian menerjemahkan setiap indeks bit ke indeks byte, untuk mengoptimalkan kecepatan.
Lundin
2
Sedangkan untuk big / little endian, big endian akan memetakan integer dan data mentah (misalnya string) dengan cara yang sama: msb kiri ke kanan ke lsb di seluruh bitmap keseluruhan. Sementara little endian akan memetakan integer kiri ke kanan sebagai 7-0, 15-8, 23-18, 31-24, tetapi data mentah masih dari kiri ke kanan msb ke lsb. Jadi betapa sedikit endian lebih baik untuk algoritma khusus Anda benar-benar di luar saya, tampaknya sebaliknya.
Lundin
2
@R .. Sebuah tabel dapat berguna jika plattform Anda tidak dapat bergeser secara efisien, seperti microchip MCU lama, tetapi tentu saja pembagian dalam sampel benar-benar tidak efisien
jeb
12

Gunakan ini:

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

    return num;
}
Peter Mortensen
sumber
5
Yah, itu menggunakan percabangan yang tidak efisien.
asdf
3
@asdf Pekerjaan kompiler adalah untuk menghasilkan biner yang paling efisien, tugas programmer adalah menulis kode yang jelas
MM
3
Ini adalah demonstrasi pengujian, pengaturan, dan pembersihan yang baik. Namun itu pendekatan yang sangat buruk untuk sedikit beralih.
Ben Voigt
10

Memperluas bitsetjawaban:

#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;
}
kendotwill
sumber
10

Jika Anda ingin melakukan semua operasi ini dengan pemrograman C di kernel Linux maka saya sarankan untuk menggunakan API standar dari kernel Linux.

Lihat 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

Catatan: Di sini seluruh operasi terjadi dalam satu langkah. Jadi ini semua dijamin atom bahkan di komputer SMP dan berguna untuk menjaga koherensi di seluruh prosesor.

Jeegar Patel
sumber
9

Visual C 2010, dan mungkin banyak kompiler lain, memiliki dukungan langsung untuk operasi boolean bawaan. Sedikit memiliki dua nilai yang mungkin, seperti halnya boolean, jadi kita dapat menggunakan boolean sebagai gantinya - bahkan jika mereka mengambil lebih banyak ruang daripada satu bit di memori dalam representasi ini. Ini berfungsi, bahkan sizeof()operator bekerja dengan baik.

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

Jadi, untuk pertanyaan Anda IsGph[i] =1,, atau IsGph[i] =0buat pengaturan dan pembersihan bools menjadi mudah.

Untuk menemukan karakter yang tidak patut dicetak:

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

Perhatikan tidak ada "khusus" tentang kode ini. Ini memperlakukan sedikit seperti bilangan bulat - yang secara teknis, itu. Bilangan bulat 1 bit yang dapat menampung 2 nilai, dan 2 nilai saja.

Saya pernah menggunakan pendekatan ini untuk menemukan catatan pinjaman duplikat, di mana nomor pinjaman adalah kunci ISAM, menggunakan nomor pinjaman 6 digit sebagai indeks ke dalam bit array. Sangat cepat, dan setelah 8 bulan, membuktikan bahwa sistem mainframe yang kami peroleh data ternyata tidak berfungsi. Kesederhanaan bit array membuat kepercayaan pada kebenarannya sangat tinggi - vs pendekatan pencarian misalnya.

Pasang kembali Monica
sumber
std :: bitset benar-benar diimplementasikan sebagai bit oleh kebanyakan kompiler
galinette
@galinette, Setuju. File header #include <bitset> adalah sumber yang bagus dalam hal ini. Juga, vektor kelas khusus <bool> ketika Anda membutuhkan ukuran vektor untuk berubah. C ++ STL, Edisi ke-2, Nicolai M. Josuttis membahasnya secara mendalam pada pgs masing-masing 650 dan 281. C ++ 11 menambahkan beberapa kemampuan baru ke std :: bitset, yang menarik bagi saya adalah fungsi hash dalam wadah yang tidak berurutan. Terimakasih atas peringatannya! Saya akan menghapus komentar kram otak saya. Sudah cukup sampah di web. Saya tidak ingin menambahkannya.
3
Ini menggunakan setidaknya satu byte seluruh penyimpanan untuk masing-masing bool. Mungkin bahkan 4 byte untuk pengaturan C89 yang digunakan intuntuk mengimplementasikanbool
MM
@MattMcNabb, Anda benar. Dalam C ++ ukuran tipe int yang diperlukan untuk mengimplementasikan boolean tidak ditentukan oleh standar. Saya menyadari jawaban ini salah beberapa waktu lalu, tetapi memutuskan untuk meninggalkannya di sini karena orang-orang tampaknya menganggapnya berguna. Bagi mereka yang ingin menggunakan komentar bit galinette sangat membantu seperti perpustakaan bit saya di sini ... stackoverflow.com/a/16534995/1899861
2
@RocketRoy: Mungkin layak mengubah kalimat yang mengklaim ini adalah contoh "operasi bit", kalau begitu.
Ben Voigt
6

Gunakan salah satu operator seperti yang didefinisikan di sini .

Untuk mengatur bit, digunakan di int x = x | 0x?;mana ?posisi bit dalam bentuk biner.

Jason
sumber
2
0xadalah awalan untuk literal dalam heksadesimal, bukan biner.
Ben Voigt
5

Berikut beberapa makro yang saya gunakan:

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)
sam msft
sumber
5

Variabel yang digunakan

int value, pos;

value - Data
pos - posisi bit yang ingin kami atur, hapus atau alihkan.

Tetapkan sedikit:

value = value | 1 << pos;

Hapus sedikit:

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

Beralih sedikit:

value = value ^ 1 << pos;
Jeet Parikh
sumber
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);
}
Sazzad Hissain Khan
sumber
Jenis pengembalian check_nth_bitbisa bool.
Xeverous
@Banyak ya itu tergantung pada niat penelepon
Sazzad Hissain Khan
5

Misalkan beberapa hal pertama
num = 55 Integer untuk melakukan operasi bitwise (set, get, clear, toggle).
n = 4Posisi bit berbasis 0 untuk melakukan operasi bitwise.

Bagaimana cara mendapatkan sedikit?

  1. Untuk mendapatkan nthsedikit pergeseran kanan num, nkali. Kemudian lakukan bitwise AND &dengan 1.
bit = (num >> n) & 1;

Bagaimana itu bekerja?

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

Bagaimana cara mengatur sedikit?

  1. Untuk mengatur sedikit angka tertentu. Pergeseran kiri 1 nkali. Kemudian lakukan operasi ATAU bitwise |dengan num.
num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

Bagaimana itu bekerja?

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

Bagaimana cara menghapusnya?

  1. Shift kiri 1, nkali yaitu 1 << n.
  2. Lakukan pelengkap bitwise dengan hasil di atas. Sehingga bit ke-n menjadi tidak disetel dan sisa bit menjadi diatur yaitu~ (1 << n) .
  3. Akhirnya, lakukan &operasi bitwise DAN dengan hasil di atas dan num. Tiga langkah di atas bersama-sama dapat ditulis sebagai num & (~ (1 << n));

Langkah-langkah untuk menghapus sedikit

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

Bagaimana itu bekerja?

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

Bagaimana cara beralih sedikit?

Untuk beralih sedikit kami menggunakan ^operator XOR bitwise . Operator Bitwise XOR mengevaluasi ke 1 jika bit yang sesuai dari kedua operan berbeda, jika tidak dievaluasi menjadi 0.

Yang berarti untuk beralih sedikit, kita perlu melakukan operasi XOR dengan bit yang ingin Anda toggle dan 1.

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

Bagaimana itu bekerja?

  • Jika bit to toggle adalah 0 maka 0 ^ 1 => 1,.
  • Jika bit toggle adalah 1 maka 1 ^ 1 => 0,.
       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     ^ 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

Dianjurkan membaca - Latihan operator Bitwise

Pankaj Prakash
sumber
Terima kasih untuk penjelasan rinci. Berikut ini tautan untuk masalah latihan untuk tautan
Chandra Shekhar
4

Bagaimana Anda mengatur, menghapus, dan beralih sedikit pun?

Untuk mengatasi perangkap kode yang umum ketika mencoba untuk membentuk topeng:
1tidak selalu cukup lebar

Masalah apa yang terjadi ketika numbertipe yang lebih luas dari itu 1?
xmungkin terlalu bagus untuk perubahan 1 << xmenuju perilaku tidak terdefinisi (UB). Sekalipun xtidak terlalu hebat, ~mungkin tidak cukup membalik bit paling signifikan.

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

Untuk memastikan 1 cukup lebar:

Kode dapat digunakan 1ullatau dengan pedantik (uintmax_t)1dan membiarkan kompiler mengoptimalkan.

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

Atau para pemain - yang membuat masalah pengkodean / review / pemeliharaan menjaga para pemain agar tetap benar dan terbaru.

number |= (type_of_number)1 << x;

Atau dengan lembut mempromosikan 1dengan memaksa operasi matematika yang paling tidak selebar jenis number.

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

Seperti kebanyakan sedikit manipulasi, terbaik untuk bekerja dengan unsigned jenis daripada ditandatangani yang

chux - Pasang kembali Monica
sumber
Tampilan menarik pada pertanyaan lama! Tidak number |= (type_of_number)1 << x;juga tidak number |= (number*0 + 1) << x;tepat untuk mengatur bit tanda dari jenis yang ditandatangani ... Sebenarnya, tidak juga number |= (1ull << x);. Apakah ada cara portabel untuk melakukannya dengan posisi?
chqrlie
1
@chqrlie IMO, cara terbaik untuk menghindari pengaturan bit tanda dan mempertaruhkan UB atau IDB dengan shift adalah dengan menggunakan tipe yang tidak ditandatangani . Kode bertanda shift yang sangat portabel terlalu berbelit-belit untuk dapat diterima.
chux - Reinstate Monica
3

Versi templat C ++ 11 (dimasukkan dalam header):

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;}
}
Joakim L. Christiansen
sumber
Kode ini rusak. (Juga, mengapa Anda memiliki ;setelah definisi fungsi Anda?)
melpomene
@melpomene Kode tidak rusak, saya sudah mengujinya. Apakah maksud Anda itu tidak akan dikompilasi atau hasilnya salah? Tentang ekstra ';' Saya tidak ingat, itu memang bisa dihilangkan.
Joakim L. Christiansen
(variable & bits == bits)?
melpomene
Terima kasih telah memperhatikan, itu seharusnya((variable & bits) == bits)
Joakim L. Christiansen
gunakan std::bitsetdi c ++ 11
pqnet
0

Program ini didasarkan pada solusi @ Jeremy di atas. Jika seseorang ingin bermain-main dengan cepat.

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
Balaji Boggaram Ramanarayan
sumber
-2

Coba salah satu dari fungsi ini dalam bahasa C untuk mengubah n bit:

char bitfield;

// Start at 0th position

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

Atau

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

Atau

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;
}
Vincet
sumber
value << ndapat menyebabkan perilaku yang tidak terdefinisi
MM