C / C ++ sprawdź, czy ustawiony jest jeden bit, tj. Zmienna int

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

Czy istnieje taki sposób, aby sprawdzić, czy bit 3 w temp jest 1 czy 0 bez przesuwania bitów i maskowania.

Chcę tylko wiedzieć, czy jest do tego jakaś wbudowana funkcja, czy też jestem zmuszony napisać ją sam.

Mediolan
źródło

Odpowiedzi:

160

W C, jeśli chcesz ukryć manipulację bitami, możesz napisać makro:

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

i użyj go w ten sposób, aby sprawdzić n- ty bit od prawego końca:

CHECK_BIT(temp, n - 1)

W C ++ możesz użyć std :: bitset .

mouviciel
źródło
3
Jeśli potrzebujesz prostej wartości prawdy, powinna to być !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu
10
@Eduard: w C wszystko != 0jest prawdą, więc po co? 1jest tak samo prawdziwe jak 0.1415!
Christoph,
1
A jeśli używasz C ++, możesz (powinieneś) napisać szablon zamiast makra. :)
jalf
2
W C to jest w porządku. Ale tego rodzaju makra w C ++. To okropne i tak podatne na nadużycia. Użyj std :: bitset
Martin York,
1
ale zestaw bitów musi znać rozmiar w czasie kompilacji
graywolf
87

Sprawdź, czy ustawiony jest bit N (zaczynając od 0):

temp & (1 << N)

Nie ma do tego wbudowanej funkcji.

Joao da Silva
źródło
16
+1 za wzmiankę, że zaczyna się od 0, ponieważ podejrzewam, że PO myślał w oparciu o 1, a zaakceptowana odpowiedź wpędzi go w kłopoty. :)
Jim Buck
Hm. Dlaczego zaczyna się od 0? Co otrzymamy, kiedy 1 << 0?? Przepraszam, zmieszany.
Danijel
6
Ok, rozumiem. Zaczynamy od pozycji 0, czyli 1<<01 bez żadnej zmiany (zmiana 0), czyli1<<0 == 1
Danijel
27

Po prostu użyłbym zestawu std :: bitset, jeśli jest to C ++. Prosty. Bezpośredni. Nie ma szans na głupie błędy.

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

albo co powiesz na tę głupotę

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);
user21714
źródło
4
@ user21714 Chyba chodziło o std :: bitset <8 * sizeof (int)>
iNFINITEi
lub std :: numeric_limits <int> :: digits
Léo Lam
@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>być jeszcze bardziej poprawnym
Xeverous
14

Tak, wiem, że nie „muszę” tego robić w ten sposób. Ale zazwyczaj piszę:

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

Na przykład:

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

Między innymi takie podejście:

  • Obsługuje 8/16/32/64 bitowe liczby całkowite.
  • Wykrywa wywołania IsBitSet (int32, int64) bez mojej wiedzy i zgody.
  • Wbudowany szablon, więc żadna funkcja nie wywołuje obciążenia.
  • const i referencje, więc nic nie musi być powielane / kopiowane. I mamy gwarancję, że kompilator wykryje wszelkie literówki, które próbują zmienić argumenty.
  • 0! = Sprawia, że ​​kod jest bardziej przejrzysty i oczywisty. Głównym celem pisania kodu jest zawsze jasna i wydajna komunikacja z innymi programistami, w tym z mniejszymi umiejętnościami.
  • Chociaż nie ma to zastosowania w tym konkretnym przypadku ... Ogólnie funkcje oparte na szablonach pozwalają uniknąć problemu wielokrotnego oceniania argumentów. Znany problem z niektórymi makrami #define.
    Np .: # zdefiniować ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);
Panie Ree
źródło
14

To, co robi wybrana odpowiedź, jest w rzeczywistości złe. Poniższa funkcja zwróci pozycję bitu lub 0 w zależności od tego, czy bit jest faktycznie włączony. Nie o to prosił plakat.

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

Oto, czego pierwotnie szukał plakat. Poniższa funkcja zwróci 1 lub 0, jeśli bit jest włączony, a nie pozycja.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
szokujący92
źródło
1
Minęło trochę czasu, zanim zrozumiałem, co masz na myśli. Dokładniej: pierwsza funkcja zwraca 2 do potęgi pozycji bitu, jeśli bit jest ustawiony, a 0 w przeciwnym razie.
lukasl1991
1
To jest dokładnie ten problem, który właśnie napotkałem, używając go w taki sposób, jak bool has_feature = CHECK_BIT(register, 25);Dobrze wiedzieć, że mogę to zrobić bez podwójnego negacji.
Jimmio92
11

Zgodnie z tym opisem pól bitowych istnieje metoda bezpośredniego definiowania i uzyskiwania dostępu do pól. Przykład w tym wpisie brzmi:

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

Jest tam również ostrzeżenie:

Jednak elementy bitowe w strukturach mają praktyczne wady. Po pierwsze, kolejność bitów w pamięci zależy od architektury, a zasady wypełniania pamięci różnią się w zależności od kompilatora. Ponadto wiele popularnych kompilatorów generuje nieefektywny kod do odczytywania i zapisywania składowych bitów, a także istnieją potencjalnie poważne problemy z bezpieczeństwem wątków związane z polami bitów (szczególnie w systemach wieloprocesorowych), ponieważ większość maszyn nie może manipulować dowolnymi zestawami bitów w pamięci, ale zamiast tego musi ładować i przechowywać całe słowa.

gimel
źródło
5

Użyj 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;
}
Martin York
źródło
1
Kilka rzeczy, o których warto tutaj wspomnieć - bity [3] dają czwarty bit - licząc od LSB do MSB. Mówiąc luźno, da ci to 4 bity licząc od prawej do lewej. Ponadto sizeof (int) podaje liczbę znaków w int, więc musiałby to być std :: bitset <sizeof (int) * CHAR_BITS> bits (temp) i bits [sizeof (int) * CHAR_BITS - 3] aby przetestować trzeci bit licząc od MSB do LSB, co jest prawdopodobnie celem.
plastikowy chris
2
Tak, ale myślę, że osoba pytająca (i osoby pochodzące z wyszukiwań w Google) mogą nie mieć takich umiejętności, a Twoja odpowiedź może ich wprowadzić w błąd.
plastikowy chris
Ta odpowiedź jest okropna. Powinien zostać usunięty.
Adam Burry
Czy wartość nie tempmusi być odzwierciedlona, ​​aby uczynić ją „gruboziarnistą”?
jww
4

Jest, a mianowicie najbardziej zawzięta instrukcja wewnętrzna.

Dave Van den Eynde
źródło
3
Łącze wskazuje „Specyficzne dla firmy Microsoft”. Używaj go tylko wtedy, gdy nie potrzebujesz przenośnego kodu.
mouviciel
Łącze wskazuje „Specyficzne dla firmy Microsoft”, ale jest to element wewnętrzny przejęty z kompilatora C ++ firmy Intel i skutkuje instrukcją BT, więc można to zrobić również za pomocą wbudowanego asemblera. Oczywiście to nie czyni go bardziej przenośnym.
Dave Van den Eynde
1
Jest to również specyficzne dla architektury x86. Więc nie, zdecydowanie nie przenośny.
jalf
Jestem pewien, że inne architektury mają podobne opcje.
Dave Van den Eynde
Istotą elementów wewnętrznych jest to, że wykorzystują sprzęt, jeśli on istnieje, i używają wymiany oprogramowania, jeśli sprzęt go nie obsługuje.
Eclipse
4

Używam tego:

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

gdzie „pos” jest zdefiniowane jako 2 ^ n (ig 1,2,4,8,16,32 ...)

Zwraca: 1 jeśli prawda 0 jeśli fałsz

AnthropicDream
źródło
2
Myślę, że to jedyna poprawna odpowiedź zarówno dla C, jak i C ++. Jako jedyny spełnia wymóg „... bez przesuwania i maskowania bitów” . Prawdopodobnie powinieneś wyraźnie określić, aby użyć 4 = 2^(3-1)pozycji bitu 3, ponieważ było to częścią pytania.
jww
3

Próbowałem odczytać 32-bitową liczbę całkowitą, która definiowała flagi obiektu w plikach PDF, ale to nie działało dla mnie

co naprawiło to zmiana definicji:

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

operand & zwraca liczbę całkowitą z flagami, które obie mają w 1, i nie był poprawnie rzutowany na wartość logiczną, to załatwiło sprawę

Ismael
źródło
!= 0zrobiłby to samo. Nie wiem, czym mogą się różnić wygenerowane instrukcje maszynowe.
Adam Burry
2

Możesz "zasymulować" przesuwanie i maskowanie: jeśli ((0x5e / (2 * 2 * 2))% 2) ...

Leonidas
źródło
Moglibyśmy posortować listę, tasując ją losowo i sprawdzając, czy jest teraz „posortowana”. Np .: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Ale my nie ...
Pan Ree
To rozwiązanie jest niezwykle marnotrawne i nieintuicyjne. Divs, Muls i Mody to trzy najdroższe funkcje. przez testy porównawcze, a i zmiany należą do najtańszych - niektóre z nielicznych, które można faktycznie wykonać w mniej niż 5 cyklach.
jheriko
Może to być (i nie jest, ponieważ nowoczesne procesory nie znoszą bitów i skoków). OP pierwotnie prosił wprost o rozwiązanie „bez przesuwania bitów i maskowania”. Więc kontynuuj i daj więcej punktów ujemnych za pasującą, ale powolną odpowiedź. Nie usunę postu tylko dlatego, że OP zmienił zdanie.
Leonidas
Wygląda na skomplikowane. Nie głosujmy przeciw tej odpowiedzi. Czasami dobrze jest poznać inne widoki.
Viet
2

W przypadku rozwiązania niskiego poziomu specyficznego dla x86 użyj kodu operacji x86 TEST .

Twój kompilator powinien jednak zmienić _bittest w to ...

jheriko
źródło
Wolałbym BT od TEST, ponieważ BT lepiej spełnia to zadanie.
u_Ltd.
1

Dlaczego nie użyć czegoś tak prostego jak to?

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

WYJŚCIE: binarne: 11111111

zeilja
źródło
jeśli jeszcze można zrobić łatwo z potrójnego: std::cout << (((status & (1 << i)) ? '1' : '0');. Powinieneś użyć CHAR_BITstałej od <climits>zamiast sztywnego kodowania 8 bitów, chociaż w tym przypadku wiesz, że wynik i tak będzie wynosić 8, ponieważ używaszuint8_t
Ryan Haining
1
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos - pozycja bitu zaczynająca się od 0.

zwraca 0 lub 1.

Artūrs Laizāns
źródło
0

jeśli chcesz naprawdę zakodować sposób:

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

zwróć uwagę na to zależne od hw i zakłada, że ​​ta kolejność bitów 7654 3210, a var wynosi 8 bitów.

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

Prowadzi do:

1 0 1 0

Szymon
źródło
1
Operacja & jest wykonywana na wartościach, które nie znajdują się w reprezentacji wewnętrznej.
Remo.D
Cześć Remo.D - Nie jesteś pewien, czy rozumiem twój komentarz? Mam kod „c”, który działa dobrze.
simon
Chodzi o to, że nie jest to zależne od sprzętu - IS_BIT3_SET zawsze będzie testować czwarty najmniej znaczący bit
Eclipse,
0

Chociaż jest już dość późno, aby odpowiedzieć teraz, istnieje prosty sposób, aby sprawdzić, czy N-ty bit jest ustawiony, czy nie, po prostu za pomocą operatorów matematycznych POWER i MODULUS.

Powiedzmy, że chcemy wiedzieć, czy „temp” ma ustawiony N-ty bit, czy nie. Poniższe wyrażenie boolowskie da wartość true, jeśli bit jest ustawiony, 0 w przeciwnym razie.

  • (moduł temp. 2 ^ N + 1> = 2 ^ N)

Rozważmy następujący przykład:

  • int temp = 0x5E; // binarnie 0b1011110 // BIT 0 to LSB

Jeśli chcę wiedzieć, czy 3. bit jest ustawiony, czy nie, otrzymuję

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

Zatem wyrażenie zwraca prawdę, wskazując, że ustawiono trzeci bit.

Ouroboros
źródło
0

Jedną z metod będzie sprawdzenie w ramach następującego warunku:

if ( (mask >> bit ) & 1)

Program wyjaśniający będzie:

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

Wynik:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set
Michi
źródło
-1

Robię to:

LATGbits.LATG0 = ((m & 0x8)> 0); // aby sprawdzić, czy bit-2 z m to 1

mathengineer
źródło
-2

najszybszym sposobem wydaje się być tablica wyszukiwania masek

oldUser
źródło