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.

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 .


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.


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

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

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)

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.



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

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.


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


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ę


!= 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) ...


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


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


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.


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


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.


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


-2

najszybszym sposobem wydaje się być tablica wyszukiwania masek

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.