C / C ++ bir bitin ayarlanıp ayarlanmadığını kontrol edin, yani int değişken


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

Bit kaydırma ve maskeleme olmadan sıcaklıktaki bit 3'ün 1 mi yoksa 0 mı olduğunu kontrol etmenin böyle bir yolu var mı?

Sadece bunun için yerleşik bir işlev olup olmadığını bilmek istiyorum, yoksa kendim bir tane yazmak zorunda mıyım?

Yanıtlar:


160

C'de, bit manipülasyonunu gizlemek istiyorsanız, bir makro yazabilirsiniz:

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

ve sağ uçtan n'inci biti kontrol etmek için bu şekilde kullanın :

CHECK_BIT(temp, n - 1)

C ++ 'da std :: bitset kullanabilirsiniz .


3
Basit bir doğruluk değerine ihtiyacınız varsa, bu olmalıdır !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu

10
@Eduard: C'de her != 0şey doğru, peki neden zahmet edelim ? 1aynen olduğu kadar doğrudur 0.1415!
Christoph

1
Ve C ++ kullanıyorsanız, makro yerine bir şablon yazabilirsiniz (yazmalısınız). :)
jalf

2
C'de bu iyidir. Ama C ++ 'da bu tür makrolar. Bu korkunç ve kötüye kullanıma çok açık. Std :: bitset'i kullanın
Martin York

1
ancak bit setinin derleme zamanında boyutu bilmesi gerekiyor
graywolf

87

Bit N'nin (0'dan başlayarak) ayarlanıp ayarlanmadığını kontrol edin:

temp & (1 << N)

Bunun yerleşik bir işlevi yoktur.


16
OP'nin 1 temelli düşündüğünden ve kabul edilen yanıtın onu başını belaya sokacağından şüphelendiğim için 0'dan başladığından bahsettiğim için +1. :)
Jim Buck

Hm. Bu neden 0'dan başlıyor? Ne zaman ne alacağız 1 << 0? Üzgünüm, kafam karıştı.
Danijel

6
Tamam anladım. 0'ıncı olasılıktan başlıyoruz, yani 1<<0herhangi bir vardiya olmadan (0'a kayma) 1<<0 == 1
Danijel

27

C ++ ise sadece std :: bitset kullanırdım. Basit. Basit. Aptalca hatalar yapma şansı yok.

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

ya da bu aptallığa ne dersin

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 Sanırım std demek istediniz :: bitset <8 * sizeof (int)>
iNFINITEi

veya std :: numeric_limits <int> :: digits
Léo Lam

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>daha da doğru olacak
Xeverous

14

Evet, ben biliyorum "var" bu şekilde yapmak. Ama genellikle yazarım:

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

Örneğin:

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

Diğer şeylerin yanı sıra, bu yaklaşım:

  • 8/16/32/64 bit tam sayıları barındırır.
  • Bilgim ve iznim olmadan IsBitSet (int32, int64) çağrılarını algılar.
  • Satır İçi Şablon, dolayısıyla ek yükü çağıran işlev yok.
  • const & hiçbir şey şimdiye referanslar, ihtiyaçlar çoğaltılmıştır / kopyalandı. Ve derleyicinin argümanları değiştirmeye çalışan herhangi bir yazım hatasını alacağına dair garantimiz var.
  • 0! = Kodu daha net ve anlaşılır hale getirir. Kod yazmanın birincil amacı, daha az beceriye sahip olanlar da dahil olmak üzere diğer programcılarla her zaman net ve verimli bir şekilde iletişim kurmaktır.
  • Bu özel durum için geçerli olmasa da ... Genelde şablonlu işlevler, argümanları birden çok kez değerlendirme sorunundan kaçınır. Bazı #define makrolarıyla ilgili bilinen bir sorun.
    Örneğin: # tanımla ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

14

Seçilen cevabın yaptığı şey aslında yanlış. Aşağıdaki fonksiyon, bitin gerçekten etkin olup olmamasına bağlı olarak bit konumunu veya 0'ı döndürecektir. Posterin istediği bu değil.

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

İşte posterin asıl aradığı şey. Aşağıdaki fonksiyon, bit etkinse ve konum değil 1 veya 0 döndürür.

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

1
Ne demek istediğini anlamam biraz zaman aldı. Daha kesin: İlk fonksiyon, bit ayarlanmışsa bit konumunun kuvvetine 2, aksi halde 0 döndürür.
lukasl1991

1
Bu, bool has_feature = CHECK_BIT(register, 25);onu çift olumsuzlama olmadan yapabileceğimi bilmek Good gibi kullanırken karşılaştığım tam sorun .
Jimmio92

11

Bit alanlarının bu açıklamasına göre , alanları doğrudan tanımlamak ve bunlara erişmek için bir yöntem vardır. Bu girişteki örnek şöyledir:

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

Ayrıca orada bir uyarı var:

Bununla birlikte, yapılardaki bit üyelerinin pratik dezavantajları vardır. İlk olarak, bellekteki bitlerin sıralaması mimariye bağlıdır ve bellek doldurma kuralları derleyiciden derleyiciye değişir. Ek olarak, birçok popüler derleyici, bit üyelerini okumak ve yazmak için verimsiz kod üretir ve çoğu makinenin bellekteki keyfi bit kümelerini işleyememesi nedeniyle bit alanlarıyla ilgili (özellikle çok işlemcili sistemlerde) potansiyel olarak ciddi iş parçacığı güvenliği sorunları vardır. ancak bunun yerine tam kelimeleri yüklemeli ve saklamalıdır.



5

Std :: bitset kullanın

#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
Burada bahsetmeye değer birkaç şey - bitler [3] size LSB'den MSB'ye kadar olan 4. biti verecektir. Gevşek bir şekilde söylemek gerekirse, size sağdan sola doğru sayan 4. biti verecektir. Ayrıca sizeof (int), bir int içindeki karakter sayısını verir, bu nedenle std :: bitset <sizeof (int) * CHAR_BITS> bit (temp) ve bit [sizeof (int) * CHAR_BITS - 3] olması gerekir. MSB'den LSB'ye 3. bit sayımını test etmek için, muhtemelen amaç budur.
plastik chris

2
Evet, ama soruyu soran kişi (ve google aramalarından gelen kişiler) bu beceriye sahip olmayabilir ve cevabınız onları yanlış yönlendirebilir.
plastic chris

Bu cevap korkunç. Silinmesi gerekir.
Adam Burry

tempOnu "büyük endian" yapmak için değerin yansıtılması gerekmiyor mu?
jww

4

Yani yoktur _bittest içsel talimat.


3
Bağlantı "Microsoft'a Özgü" olduğunu gösterir. Yalnızca kodunuzun taşınabilir olmasına ihtiyacınız yoksa kullanın.
mouviciel

Bağlantı "Microsoft Özel" i gösterir, ancak bu Intel C ++ derleyicisinden devralınan bir içseldir ve bir BT komutuyla sonuçlanır, böylece bunu satır içi assembler ile de yapabilirsiniz. Elbette bu onu daha taşınabilir hale getirmez.
Dave Van den Eynde

1
Ayrıca x86 mimarisine özgüdür. Yani hayır, kesinlikle taşınabilir değil.
jalf

Eminim diğer mimarilerin de benzer seçenekleri vardır.
Dave Van den Eynde

İçsel bilginin en önemli noktası, varsa donanımdan yararlanmaları ve donanımın üstesinden gelmezse bir yazılım değiştirme kullanmalarıdır.
Eclipse

4

Bunu kullanıyorum:

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

burada "pos" 2 ^ n (ig 1,2,4,8,16,32 ...) olarak tanımlanır

Geri döndürür: 1 doğruysa 0 yanlışsa


2
Bence bu hem C hem de C ++ için tek doğru cevap. "... bit kaydırma ve maskeleme" gerekliliğine saygı duyan tek kişidir . 4 = 2^(3-1)Sorunun bir parçası olduğu için muhtemelen bit konumu 3 için kullanmayı açıkça belirtmelisiniz .
jww

3

PDF'lerdeki bir nesnenin bayraklarını tanımlayan 32 bitlik bir tamsayıyı okumaya çalışıyordum ve bu benim için çalışmıyordu

ne düzeltildi, tanımı değiştiriyordu:

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

işlenen & her ikisi de 1'de bulunan bayraklarla bir tamsayı döndürür ve boolean'a düzgün bir şekilde dönüşmüyor, bu hile yaptı


!= 0aynısını yapardı. Oluşturulan makine talimatlarının nasıl farklı olabileceğini bilmiyorum.
Adam Burry

2

Kaydırmayı ve maskelemeyi "simüle edebilirsiniz": if ((0x5e / (2 * 2 * 2))% 2) ...


Bir listeyi rastgele karıştırarak ve şimdi "sıralı" olup olmadığını görmek için test ederek sıralayabiliriz. Örneğin: while (/ * NOT * /! İsSorted ()) {RandomlyShuffle (); } Ama yapmayız ...
Bay Ree

Bu çözüm, kaynaklar için son derece savurgan ve sezgisel değildir. divs, muls ve mods en pahalı üç işlevdir. Karşılaştırma testleri ile ve vardiyalar ve vardiyalar en ucuzları arasındadır - aslında 5 döngüden daha kısa sürede tamamlayabileceğiniz birkaç tanesi.
jheriko

Bu olabilir (ve değildir, çünkü modern işlemciler bitlerden ve sıçramalardan nefret eder). OP başlangıçta açık bir şekilde "bit kaydırma ve maskeleme olmadan" bir çözüm istedi . Öyleyse devam edin ve eşleşen ancak yavaş bir cevap için daha fazla olumsuz puan verin. Sırf OP fikrini değiştirdiği için gönderiyi silmeyeceğim.
Leonidas

Zor görünüyor. Bu yanıtı oylamayalım. Bazen başka görüşleri keşfetmek iyidir.
Viet

2

Düşük seviyeli x86'ya özgü çözüm için x86 TEST işlem kodunu kullanın .

Derleyiciniz _bittest'i buna dönüştürmeli ...


BT göreve daha iyi uyduğu için TEST yerine BT'yi tercih ederim .
u_Ltd.

1

Neden bu kadar basit bir şey kullanmıyorsunuz?

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

ÇIKIŞ: ikili: 11111111


else if bir Üçlü ile kolayca yapılabilir: std::cout << (((status & (1 << i)) ? '1' : '0');. 8 biti sabit kodlamak yerine CHAR_BITsabitini kullanmalısınız <climits>, ancak bu durumda sonucun 8 olacağını biliyorsunuz çünkü auint8_t
Ryan Haining

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

pos - 0'dan başlayan bit konumu.

0 veya 1 döndürür.


0

sadece gerçek bir kodlanmış yol istiyorsanız:

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

bu hw'ye bağımlı olduğuna dikkat edin ve bu bit sırasını 7654 3210 ve var'ın 8 bit olduğunu varsayar.

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

Sonuçlar:

1 0 1 0


1
& İşlemi, dahili gösterimde olmayan değerler üzerinde yapılır.
Remo.D

Merhaba Remo.D - Yorumunuzu anladığımdan emin değil misiniz? İyi çalışan bazı 'c' kodunu ekledim.
simon

Demek istediğim, donanıma bağlı olmaması - IS_BIT3_SET her zaman 4. en az önemli biti test edecek
Eclipse

0

Şimdi cevaplamak için oldukça geç olsa da, Nth bitinin ayarlanıp ayarlanmadığını bulmanın basit bir yolu var, sadece POWER ve MODULUS matematiksel operatörleri kullanarak.

Diyelim ki 'temp'nin N'inci biti olup olmadığını bilmek istiyoruz. Aşağıdaki boole ifadesi, bit ayarlanmışsa doğru, aksi takdirde 0 verecektir.

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

Aşağıdaki örneği düşünün:

  • int temp = 0x5E; // ikili olarak 0b1011110 // BIT 0 LSB'dir

3. bitin ayarlanıp ayarlanmadığını bilmek istersem

  • (94 MODÜL 16) = 14> 2 ^ 3

Yani ifade, 3. bitin ayarlandığını göstererek true döndürür.


0

Bir yaklaşım aşağıdaki koşulda kontrol edilecektir:

if ( (mask >> bit ) & 1)

Bir açıklama programı şöyle olacaktır:

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

Çıktı:

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

-1

Ben bunu yapıyorum:

LATGbits.LATG0 = ((m & 0x8)> 0); // m'nin bit-2'sinin 1 olup olmadığını kontrol etmek için


-2

en hızlı yol, maskeler için bir arama tablosu gibi görünüyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.