C / C ++ memeriksa apakah satu bit disetel, yaitu variabel int


100
int temp = 0x5E; // in binary 0b1011110.

Apakah ada cara untuk memeriksa apakah bit 3 dalam suhu 1 atau 0 tanpa sedikit pergeseran dan masking.

Hanya ingin tahu apakah ada fungsi bawaan untuk ini, atau saya terpaksa menulisnya sendiri.

Jawaban:


157

Di C, jika Anda ingin menyembunyikan manipulasi bit, Anda dapat menulis makro:

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

dan gunakan cara ini untuk memeriksa bit ke- n dari ujung kanan:

CHECK_BIT(temp, n - 1)

Di C ++, Anda dapat menggunakan std :: bitset .


3
Jika Anda membutuhkan nilai kebenaran sederhana, itu harus !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu

10
@Eduard: di C, semuanya != 0benar, jadi mengapa repot-repot? 1sama benarnya dengan 0.1415!
Christoph

1
Dan jika Anda menggunakan C ++, Anda dapat (harus) menulis template alih-alih makro. :)
jalf

2
Di C ini bagus. Tapi jenis makro ini di C ++. Itu mengerikan dan sangat terbuka untuk pelecehan. Gunakan std :: bitset
Martin York

5
Ugh std::bitset, benarkah? Tentu, daripada melakukan sedikit pekerjaan (dan berpotensi beberapa templat yang sangat bagus) untuk memeriksa sedikit pun, gunakan wadah kembung yang menyimpan (pada implementasi saya) setiap 'bit' dalam tempat yang tidak terpakai unsigned long. Sungguh menyia-nyiakan ruang!
underscore_d

86

Periksa apakah bit N (mulai dari 0) disetel:

temp & (1 << N)

Tidak ada fungsi bawaan untuk ini.


16
+1 untuk menyebutkannya mulai dari 0 karena saya curiga OP berpikir berbasis 1 dan jawaban yang diterima akan membuatnya mendapat masalah. :)
Jim Buck

Hm. Mengapa ini dimulai dari 0? Apa yang kita dapatkan saat 1 << 0?? Maaf bingung
Danijel

6
OK mengerti. Kita mulai dari posisi 0, yaitu 1<<01 tanpa shift (shift 0), yaitu1<<0 == 1
Danijel

27

Saya hanya akan menggunakan std :: bitset jika itu C ++. Sederhana. Mudah. Tidak ada kesempatan untuk kesalahan bodoh.

typedef std::bitset<sizeof(int)> IntBits;
bool is_set = IntBits(value).test(position);

atau bagaimana dengan kekonyolan ini

template<unsigned int Exp>
struct pow_2 {
    static const unsigned int value = 2 * pow_2<Exp-1>::value;
};

template<>
struct pow_2<0> {
    static const unsigned int value = 1;
};

template<unsigned int Pos>
bool is_bit_set(unsigned int value)
{
    return (value & pow_2<Pos>::value) != 0;
} 

bool result = is_bit_set<2>(value);

4
@ user21714 Kurasa maksudmu std :: bitset <8 * sizeof (int)>
iNFINITEi

atau std :: numeric_limits <int> :: digit
Léo Lam

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>bahkan lebih tepat
Xeverous

14

Apa yang dilakukan jawaban yang dipilih sebenarnya salah. Fungsi di bawah ini akan mengembalikan posisi bit atau 0 tergantung pada apakah bit benar-benar diaktifkan. Ini bukan yang diminta poster itu.

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

Inilah yang awalnya dicari poster itu. Fungsi di bawah ini akan mengembalikan 1 atau 0 jika bit diaktifkan dan bukan posisinya.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)

1
Butuh beberapa waktu sampai saya mengerti apa yang Anda maksud. Lebih tepatnya: Fungsi pertama mengembalikan 2 pangkat posisi bit jika bit disetel, 0 sebaliknya.
lukasl1991

1
Ini adalah masalah tepat yang baru saja saya temui saat menggunakannya seperti bool has_feature = CHECK_BIT(register, 25);Senang mengetahui bahwa saya bisa melakukannya tanpa negasi ganda.
Jimmio92

13

Ya, saya tahu saya tidak "harus" melakukannya dengan cara ini. Tapi saya biasanya menulis:

    /* Return type (8/16/32/64 int size) is specified by argument size. */
template<class TYPE> inline TYPE BIT(const TYPE & x)
{ return TYPE(1) << x; }

template<class TYPE> inline bool IsBitSet(const TYPE & x, const TYPE & y)
{ return 0 != (x & y); }

Misalnya:

IsBitSet( foo, BIT(3) | BIT(6) );  // Checks if Bit 3 OR 6 is set.

Antara lain, pendekatan ini:

  • Mengakomodasi 8/16/32/64 bit integer.
  • Mendeteksi panggilan IsBitSet (int32, int64) tanpa sepengetahuan & persetujuan saya.
  • Template Inline, jadi tidak ada fungsi yang memanggil overhead.
  • const & referensi, jadi tidak ada yang perlu diduplikasi / disalin. Dan kami dijamin bahwa kompilator akan menerima kesalahan ketik apa pun yang mencoba mengubah argumen.
  • 0! = Membuat kode lebih jelas & jelas. Poin utama dalam menulis kode adalah selalu berkomunikasi dengan jelas dan efisien dengan programmer lain, termasuk mereka yang memiliki keterampilan lebih rendah.
  • Meskipun tidak berlaku untuk kasus khusus ini ... Secara umum, fungsi template menghindari masalah mengevaluasi argumen beberapa kali. Masalah yang diketahui dengan beberapa makro #define.
    Misalnya: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

11

Menurut deskripsi bidang bit ini , terdapat metode untuk menentukan dan mengakses bidang secara langsung. Contoh dalam entri ini adalah:

struct preferences {
    unsigned int likes_ice_cream : 1;
    unsigned int plays_golf : 1;
    unsigned int watches_tv : 1;
    unsigned int reads_books : 1;
}; 

struct preferences fred;

fred.likes_ice_cream = 1;
fred.plays_golf = 1;
fred.watches_tv = 1;
fred.reads_books = 0;

if (fred.likes_ice_cream == 1)
    /* ... */

Juga, ada peringatan di sana:

Namun, anggota bit dalam struct memiliki kelemahan praktis. Pertama, urutan bit dalam memori bergantung pada arsitektur dan aturan padding memori bervariasi dari compiler ke compiler. Selain itu, banyak kompiler populer menghasilkan kode yang tidak efisien untuk membaca dan menulis anggota bit, dan ada masalah keamanan thread yang berpotensi parah terkait dengan bidang bit (terutama pada sistem multiprosesor) karena fakta bahwa sebagian besar mesin tidak dapat memanipulasi kumpulan bit yang berubah-ubah dalam memori, tetapi harus memuat dan menyimpan seluruh kata.



5

Gunakan std :: bitset

#include <bitset>
#include <iostream>

int main()
{
    int temp = 0x5E;
    std::bitset<sizeof(int)*CHAR_BITS>   bits(temp);

    // 0 -> bit 1
    // 2 -> bit 3
    std::cout << bits[2] << std::endl;
}

1
Beberapa hal yang perlu disebutkan di sini - bits [3] akan memberi Anda bit ke-4 - menghitung dari LSB ke MSB. Sederhananya, ini akan memberi Anda 4 bit yang dihitung dari kanan ke kiri. Juga, sizeof (int) memberikan jumlah karakter dalam sebuah int, jadi itu harus std :: bitset <sizeof (int) * CHAR_BITS> bits (temp), dan bits [sizeof (int) * CHAR_BITS - 3] untuk menguji penghitungan bit ke-3 dari MSB ke LSB, yang mungkin merupakan maksudnya.
chris plastik

2
Ya, tapi menurut saya si penanya (dan orang-orang yang berasal dari pencarian google) mungkin tidak memiliki keahlian itu, dan jawaban Anda bisa menyesatkan mereka.
chris plastik

Jawaban ini sangat buruk. Ini harus dihapus.
Adam Burry

Bukankah nilainya tempperlu direfleksikan untuk membuatnya menjadi "big-endian"?
jww

4

Ada, yaitu instruksi intrinsik _bittest .


3
Tautan menunjukkan "Microsoft Specific". Gunakan hanya jika Anda tidak membutuhkan kode Anda untuk menjadi portabel.
mouviciel

Tautan tersebut menunjukkan "Microsoft Specific", tetapi ini adalah intrinsik yang diambil alih dari kompiler Intel C ++, dan ini menghasilkan instruksi BT, sehingga Anda dapat melakukannya dengan assembler inline juga. Tentu saja, itu tidak membuatnya lebih portabel.
Dave Van den Eynde

1
Ini juga khusus untuk arsitektur x86. Jadi tidak, jelas tidak portabel.
jalf

Saya yakin arsitektur lain memiliki opsi serupa.
Dave Van den Eynde

Inti dari intrinsik adalah mereka memanfaatkan perangkat keras jika ada, dan menggunakan pengganti perangkat lunak jika perangkat keras tidak menanganinya.
Gerhana

4

Saya menggunakan ini:

#define CHECK_BIT(var,pos) ( (((var) & (pos)) > 0 ) ? (1) : (0) )

di mana "pos" didefinisikan sebagai 2 ^ n (ig 1,2,4,8,16,32 ...)

Mengembalikan: 1 jika benar 0 jika salah


2
Saya pikir ini adalah satu-satunya jawaban yang benar untuk C dan C ++. Ini adalah satu-satunya yang menghormati persyaratan "... tanpa pergeseran dan penyamaran sedikit" . Anda mungkin harus secara eksplisit menyatakan digunakan 4 = 2^(3-1)untuk posisi bit 3 karena itu adalah bagian dari pertanyaan.
jww

3

saya mencoba membaca integer 32-bit yang menentukan bendera untuk objek dalam PDF dan ini tidak berfungsi untuk saya

yang memperbaikinya adalah mengubah definisi:

#define CHECK_BIT(var,pos) ((var & (1 << pos)) == (1 << pos))

operan & mengembalikan integer dengan flag yang keduanya ada di 1, dan tidak mentransmisikan dengan benar ke dalam boolean, ini berhasil


!= 0akan melakukan hal yang sama. Tidak tahu bagaimana instruksi mesin yang dihasilkan mungkin berbeda.
Adam Burry

2

Anda bisa "mensimulasikan" perpindahan dan pemaskeran: if ((0x5e / (2 * 2 * 2))% 2) ...


Kami dapat mengurutkan daftar dengan mengacaknya secara acak dan mengujinya untuk melihat apakah sekarang "diurutkan". Misalnya: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Tapi kami tidak ...
Mr. Ree

Solusi ini sangat boros sumber daya dan tidak intuitif. divs, muls dan mods adalah tiga fungsi yang paling mahal. dengan tes perbandingan, ands dan shift adalah yang termurah - beberapa dari sedikit yang mungkin benar-benar Anda selesaikan dalam waktu kurang dari 5 siklus.
jheriko

Itu mungkin (dan tidak, karena prosesor modern membenci bit dan lompatan). OP awalnya meminta secara eksplisit untuk solusi "tanpa perubahan sedikit pun dan penyamaran." Jadi, lanjutkan dan berikan lebih banyak poin negatif untuk jawaban yang cocok tetapi lambat. Saya tidak akan menghapus postingan hanya karena OP berubah pikiran.
Leonidas

Ini terlihat rumit. Mari kita tidak menolak jawaban ini. Terkadang bagus untuk menjelajahi pandangan lain.
Viet

2

Untuk solusi khusus x86 tingkat rendah, gunakan TEST x86 opcode .

Kompiler Anda harus mengubah _bittest menjadi ini ...


Saya lebih memilih BT daripada TEST karena BT lebih cocok dengan tugas tersebut.
u_Ltd.

1

Mengapa tidak menggunakan sesuatu yang sederhana seperti ini?

uint8_t status = 255;
cout << "binary: ";

for (int i=((sizeof(status)*8)-1); i>-1; i--)
{
  if ((status & (1 << i)))
  {
    cout << "1";
  } 
  else
  {
    cout << "0";
  }
}

OUTPUT: biner: 11111111


jika lain dapat dilakukan dengan mudah dengan ternary a: std::cout << (((status & (1 << i)) ? '1' : '0');. Anda harus menggunakan CHAR_BITkonstanta dari <climits>alih-alih pengkodean keras 8 bit, meskipun dalam hal ini Anda tahu hasilnya akan tetap 8 karena Anda menggunakanuint8_t
Ryan Haining

0

jika Anda hanya ingin cara kode keras yang nyata:

 #define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )

perhatikan hw ini tergantung dan anggap urutan bit ini 7654 3210 dan var adalah 8 bit.

#include "stdafx.h"
#define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )
int _tmain(int argc, _TCHAR* argv[])
{
    int temp =0x5E;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x00;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x04;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0xfb;
    printf(" %d \n", IS_BIT3_SET(temp));
    scanf("waitng %d",&temp);

    return 0;
}

Hasil dalam:

1 0 1 0


1
Operasi & dilakukan pada nilai-nilai bukan pada representasi internal.
Remo.D

Hai Remo.D - Tidak yakin saya mengerti komentar Anda? Saya telah menyertakan beberapa kode 'c' yang berfungsi dengan baik.
simon

Maksudnya adalah bahwa ini tidak bergantung pada perangkat keras - IS_BIT3_SET akan selalu menguji bit paling signifikan ke-4
Eclipse

0

Meskipun cukup terlambat untuk menjawabnya sekarang, ada cara sederhana untuk mengetahui apakah bit ke-N disetel atau tidak, cukup dengan menggunakan operator matematika POWER dan MODULUS.

Katakanlah kita ingin tahu apakah 'temp' memiliki bit ke-N atau tidak. Ekspresi boolean berikut akan menjadi true jika bit disetel, 0 jika tidak.

  • (suhu MODULUS 2 ^ N + 1> = 2 ^ N)

Perhatikan contoh berikut:

  • suhu int = 0x5E; // dalam biner 0b1011110 // BIT 0 adalah LSB

Jika saya ingin tahu apakah bit ke-3 disetel atau tidak, saya mengerti

  • (94 MODULUS 16) = 14> 2 ^ 3

Jadi ekspresi mengembalikan nilai true, menunjukkan bit ke-3 disetel.


0

Salah satu pendekatan akan memeriksa dalam kondisi berikut:

if ( (mask >> bit ) & 1)

Program penjelasan akan menjadi:

#include <stdio.h>

unsigned int bitCheck(unsigned int mask, int pin);

int main(void){
   unsigned int mask = 6;  // 6 = 0110
   int pin0 = 0;
   int pin1 = 1;
   int pin2 = 2;
   int pin3 = 3;
   unsigned int bit0= bitCheck( mask, pin0);
   unsigned int bit1= bitCheck( mask, pin1);
   unsigned int bit2= bitCheck( mask, pin2);
   unsigned int bit3= bitCheck( mask, pin3);

   printf("Mask = %d ==>>  0110\n", mask);

   if ( bit0 == 1 ){
      printf("Pin %d is Set\n", pin0);
   }else{
      printf("Pin %d is not Set\n", pin0);
   }

    if ( bit1 == 1 ){
      printf("Pin %d is Set\n", pin1);
   }else{
      printf("Pin %d is not Set\n", pin1);
   }

   if ( bit2 == 1 ){
      printf("Pin %d is Set\n", pin2);
   }else{
      printf("Pin %d is not Set\n", pin2);
   }

   if ( bit3 == 1 ){
      printf("Pin %d is Set\n", pin3);
   }else{
      printf("Pin %d is not Set\n", pin3);
   }
}

unsigned int bitCheck(unsigned int mask, int bit){
   if ( (mask >> bit ) & 1){
      return 1;
   }else{
      return 0;
   }
}

Keluaran:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set

0
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos - Posisi bit dimulai dari 0.

mengembalikan 0 atau 1.


-1

Saya membuat ini:

LATGbits.LATG0 = ((m & 0x8)> 0); // untuk memeriksa apakah bit-2 dari m adalah 1


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.