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 ^=(-(unsignedlong)x ^ number)&(1UL<< n);
atau
unsignedlong 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.
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.
+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).
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))
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
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 { ... };
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/typedefenum{ERROR =-1, FALSE, TRUE} LOGICAL;#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(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:
00000000000000000000000000000001 binary.
Jika posn == 8, itu akan mengevaluasi ke:
00000000000000000000000100000000 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:
#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(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;}
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.
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)))))
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.
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.
structHwRegister{unsignedint errorFlag:1;// one-bit flag fieldunsignedintMode:3;// three-bit mode fieldunsignedintStatusCode:4;// four-bit status code};structHwRegister 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.
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:
int main(void){unsignedchar 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));return0;}
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.
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).
constunsignedcharTQuickByteMask[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.
*/voidTSetBit(short bit,unsignedchar*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.
*/voidTResetBit(short bit,unsignedchar*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.
*/voidTToggleBit(short bit,unsignedchar*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.
*/shortTIsBitSet(short bit,constunsignedchar*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])return1;return0;}/** Checks specified bit.
*
* @return 1 if bit reset else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/shortTIsBitReset(short bit,constunsignedchar*bitmap){returnTIsBitSet(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).
*/intTCountBits(constunsignedchar*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...).
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:
intToggleNthBit(unsignedchar n,int num ){if(num &(1<< n))
num &=~(1<< n);else
num |=(1<< n);return num;}
set_bit Atomicallyset 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 andreturn its old value
test_and_clear_bit Clear a bit andreturn its old value
test_and_change_bit Change a bit andreturn its old value
test_bit Determine whether a bit isset
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.
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.
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.
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.
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?
Untuk mendapatkan nthsedikit pergeseran kanan num, nkali. Kemudian lakukan bitwise AND &dengan 1.
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);
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/unsignedunsignedlonglong 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
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.
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.
Jawaban:
Pengaturan sedikit
Gunakan bitwise OR operator (
|
) untuk mengatur bit.Itu akan mengatur
n
bit thnumber
.n
harus nol, jika Anda ingin mengatur1
bit st dan seterusnyan-1
, jika Anda ingin mengaturn
bit th.Gunakan
1ULL
jikanumber
lebih luas dariunsigned long
; promosi1UL << n
tidak terjadi sampai setelah mengevaluasi di1UL << n
mana perilaku yang tidak ditentukan untuk bergeser lebih dari lebar along
. Hal yang sama berlaku untuk semua contoh lainnya.Bersihkan sedikit
Gunakan bitwise AND operator (
&
) untuk menghapus sedikit.Itu akan menghapus
n
sedikitnumber
. Anda harus membalikkan string bit dengan operator NOT bitwise (~
), lalu DAN itu.Beralih sedikit
Operator XOR (
^
) dapat digunakan untuk beralih sedikit.Itu akan beralih
n
sedikitnumber
.Memeriksa sedikit
Anda tidak meminta ini, tetapi saya mungkin juga menambahkannya.
Untuk memeriksa sedikit, geser angka n ke kanan, lalu bitwise DAN itu:
Itu akan menempatkan nilai
n
bitnumber
ke dalam variabelbit
.Mengubah n th bit untuk x
Mengatur
n
bit th ke salah satu1
atau0
dapat dicapai dengan yang berikut pada implementasi C ++ 2 komplemen:Bit
n
akan ditetapkan jikax
ini1
, dan dibersihkan jikax
ini0
. Jikax
memiliki nilai lain, Anda mendapatkan sampah.x = !!x
akan mendudukkannya menjadi 0 atau 1.Untuk menjadikan ini tidak tergantung pada perilaku negasi komplemen 2 (di mana
-1
semua bit diatur, tidak seperti pada komplemen 1 atau implementasi sign / magnitude C ++), gunakan negasi yang tidak ditandatangani.atau
Ini umumnya ide yang baik untuk menggunakan tipe yang tidak ditandatangani untuk manipulasi bit portabel.
atau
(number & ~(1UL << n))
akan menghapusn
bit th dan(x << n)
akan mengaturn
bit th kex
.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.
sumber
bit = (number >> x) & 1
1
adalahint
literal, 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 digunakan1U
.number = number & ~(1 << n) | (x << n);
untuk Mengubah bit ke-x ke x.Menggunakan Standard C ++ Library:
std::bitset<N>
.Atau Meningkatkan versi:
boost::dynamic_bitset
.Tidak perlu menggulung sendiri:
Versi Boost memungkinkan bitet berukuran runtime dibandingkan dengan bitet berukuran waktu kompilasi pustaka standar .
sumber
Opsi lainnya adalah menggunakan bidang bit:
mendefinisikan bidang 3-bit (sebenarnya, itu tiga bidang 1-bit). Operasi bit sekarang menjadi sedikit (haha) lebih sederhana:
Untuk mengatur atau menghapus sedikit:
Untuk beralih sedikit:
Memeriksa sedikit:
Ini hanya bekerja dengan bidang bit ukuran tetap. Kalau tidak, Anda harus menggunakan teknik bit-twiddling yang dijelaskan dalam posting sebelumnya.
sumber
Saya menggunakan makro yang didefinisikan dalam file header untuk menangani bit yang diatur dan dihapus:
sumber
BITMASK_CHECK(x,y) ((x) & (y))
harus((x) & (y)) == (y)
dinyatakan sebaliknya mengembalikan hasil yang salah pada multibit mask (mis.5
vs.3
) / * Halo untuk semua penggali kubur1
harus(uintmax_t)1
serupa atau seandainya ada yang mencoba menggunakan makro ini padalong
tipe yang lebih besarBITMASK_CHECK_ALL(x,y)
dapat diimplementasikan sebagai!~((~(y))|(x))
!(~(x) & (y))
Kadang-kadang layak digunakan
enum
untuk menamai bit:Kemudian gunakan nama nanti. Yaitu menulis
untuk mengatur, menghapus, dan menguji. Dengan cara ini Anda menyembunyikan angka ajaib dari sisa kode Anda.
Selain itu saya mendukung solusi Jeremy.
sumber
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?enum
s untuk set konstanta terkait kembali pada pemrograman c. Saya menduga bahwa dengan kompiler modern satu-satunya keuntungan di atasconst short
atau 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.enum ThingFlags
gunanyaThingError|ThingFlag1
, misalnya?int
. Ini dapat menyebabkan segala macam bug halus karena promosi integer implisit atau operasi bitwise pada tipe yang ditandatangani.thingstate = ThingFlag1 >> 1
misalnya akan meminta perilaku yang ditentukan implementasi.thingstate = (ThingFlag1 >> x) << y
dapat memanggil perilaku yang tidak terdefinisi. Dan seterusnya. Agar aman, selalu dilemparkan ke jenis yang tidak ditandatangani.enum My16Bits: unsigned short { ... };
Dari bitip.h snip-c.zip:
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:
Jika posn == 8, itu akan mengevaluasi ke:
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] ----------------------------------------- -----------------------
---- [TEST.OUT (dibongkar)] -------------------------------------- ---------
---- [finis] ------------------------------------------- ----------------------
sumber
arg
adalong long
.1L
perlu jenis seluas mungkin, jadi(uintmax_t)1
. (Anda mungkin lolos1ull
)Gunakan operator bitwise:
&
|
Untuk mengatur bit terakhir di
000b
:Untuk memeriksa bit terakhir di
foo
:Untuk menghapus bit terakhir di
foo
:Saya menggunakan
XXXb
untuk kejelasan. Anda mungkin akan bekerja dengan representasi HEX, tergantung pada struktur data tempat Anda mengemas bit.sumber
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
Untuk pemula, saya ingin menjelaskan sedikit lebih banyak dengan contoh:
Contoh:
The
&
operator yang digunakan memeriksa bit:Beralih atau Balik:
|
operator: atur bitnyasumber
Inilah makro aritmatika bit favorit saya, yang berfungsi untuk semua jenis bilangan bulat tak bertanda dari
unsigned char
hinggasize_t
(yang merupakan jenis terbesar yang harus efisien untuk bekerja dengannya):Untuk mengatur sedikit:
Untuk menghapus sedikit:
Untuk beralih sedikit:
Untuk menguji sedikit:
dll.
sumber
BITOP(array, bit++, |=);
dalam satu lingkaran kemungkinan besar tidak akan melakukan apa yang diinginkan pemanggil.BITCELL(a,b) |= BITMASK(a,b);
(keduanya mengambila
sebagai argumen untuk menentukan ukuran, tetapi yang terakhir tidak akan pernah mengevaluasia
karena hanya muncul disizeof
).(size_t)
pemain tampaknya berada di sana hanya untuk memastikan beberapa matematika unsigned dengan%
. Bisa di(unsigned)
sana(size_t)(b)/(8*sizeof *(a))
tidak perlu bisa menyempitb
sebelum divisi. Hanya masalah dengan bit array yang sangat besar. Masih makro yang menarik.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.
sumber
volatile
dan 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.Pendekatan bitfield memiliki kelebihan lain di arena tertanam. Anda dapat mendefinisikan struct yang memetakan langsung ke bit dalam register perangkat keras tertentu.
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.
sumber
Periksa sedikit di lokasi sewenang-wenang dalam variabel tipe sewenang-wenang:
Penggunaan sampel:
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.
sumber
Lebih umum, untuk bitmap berukuran acak:
sumber
CHAR_BIT
sudah ditentukan olehlimits.h
, Anda tidak perlu memasukkannya sendiriBITS
(dan faktanya membuat kode Anda lebih buruk dengan melakukannya)Program ini untuk mengubah bit data apa saja dari 0 menjadi 1 atau 1 menjadi 0:
sumber
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).
Catatan, untuk mengatur bit 'n' dalam bilangan bulat 16 bit Anda melakukan hal berikut:
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...).
sumber
Gunakan ini:
sumber
Memperluas
bitset
jawaban:sumber
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
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.
sumber
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.Jadi, untuk pertanyaan Anda
IsGph[i] =1
,, atauIsGph[i] =0
buat pengaturan dan pembersihan bools menjadi mudah.Untuk menemukan karakter yang tidak patut dicetak:
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.
sumber
bool
. Mungkin bahkan 4 byte untuk pengaturan C89 yang digunakanint
untuk mengimplementasikanbool
Gunakan salah satu operator seperti yang didefinisikan di sini .
Untuk mengatur bit, digunakan di
int x = x | 0x?;
mana?
posisi bit dalam bentuk biner.sumber
0x
adalah awalan untuk literal dalam heksadesimal, bukan biner.Berikut beberapa makro yang saya gunakan:
sumber
Variabel yang digunakan
value - Data
pos - posisi bit yang ingin kami atur, hapus atau alihkan.
Tetapkan sedikit:
Hapus sedikit:
Beralih sedikit:
sumber
sumber
check_nth_bit
bisabool
.Bagaimana cara mendapatkan sedikit?
nth
sedikit pergeseran kanannum
,n
kali. Kemudian lakukan bitwise AND&
dengan 1.Bagaimana itu bekerja?
Bagaimana cara mengatur sedikit?
n
kali. Kemudian lakukan operasi ATAU bitwise|
dengannum
.Bagaimana itu bekerja?
Bagaimana cara menghapusnya?
n
kali yaitu1 << n
.~ (1 << n)
.&
operasi bitwise DAN dengan hasil di atas dannum
. Tiga langkah di atas bersama-sama dapat ditulis sebagainum & (~ (1 << n))
;Bagaimana itu bekerja?
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.
Bagaimana itu bekerja?
0 ^ 1 => 1
,.1 ^ 1 => 0
,.Dianjurkan membaca - Latihan operator Bitwise
sumber
Untuk mengatasi perangkap kode yang umum ketika mencoba untuk membentuk topeng:
1
tidak selalu cukup lebarMasalah apa yang terjadi ketika
number
tipe yang lebih luas dari itu1
?x
mungkin terlalu bagus untuk perubahan1 << x
menuju perilaku tidak terdefinisi (UB). Sekalipunx
tidak terlalu hebat,~
mungkin tidak cukup membalik bit paling signifikan.Untuk memastikan 1 cukup lebar:
Kode dapat digunakan
1ull
atau dengan pedantik(uintmax_t)1
dan membiarkan kompiler mengoptimalkan.Atau para pemain - yang membuat masalah pengkodean / review / pemeliharaan menjaga para pemain agar tetap benar dan terbaru.
Atau dengan lembut mempromosikan
1
dengan memaksa operasi matematika yang paling tidak selebar jenisnumber
.Seperti kebanyakan sedikit manipulasi, terbaik untuk bekerja dengan unsigned jenis daripada ditandatangani yang
sumber
number |= (type_of_number)1 << x;
juga tidaknumber |= (number*0 + 1) << x;
tepat untuk mengatur bit tanda dari jenis yang ditandatangani ... Sebenarnya, tidak juganumber |= (1ull << x);
. Apakah ada cara portabel untuk melakukannya dengan posisi?Versi templat C ++ 11 (dimasukkan dalam header):
sumber
;
setelah definisi fungsi Anda?)(variable & bits == bits)
?((variable & bits) == bits)
std::bitset
di c ++ 11Program ini didasarkan pada solusi @ Jeremy di atas. Jika seseorang ingin bermain-main dengan cepat.
sumber
Coba salah satu dari fungsi ini dalam bahasa C untuk mengubah n bit:
Atau
Atau
sumber
value << n
dapat menyebabkan perilaku yang tidak terdefinisi