C / C ++ перевірте, чи встановлений один біт, тобто змінна int


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

Чи існує такий спосіб перевірити, чи є біт 3 у темпі 1 або 0 без зміщення бітів та маскування.

Просто хочу знати, чи є для цього якась вбудована функція, або я змушений писати її сам.

Відповіді:


157

У C, якщо ви хочете приховати біт-маніпуляцію, ви можете написати макрос:

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

і скористайтеся цим способом для перевірки n- го біта з правого кінця:

CHECK_BIT(temp, n - 1)

У C ++ ви можете використовувати std :: bitset .


3
Якщо вам потрібне просте значення істини, воно повинно бути !! ((var) & (1 << (pos))).
Едуард - Габріель Мунтяну

10
@Eduard: у C все != 0правда, так навіщо турбуватися? 1точно так само, як 0.1415!
Крістоф

1
І якщо ви використовуєте C ++, ви можете (повинні) написати шаблон замість макросу. :)
jalf

2
В С це добре. Але цей вид макросів у C ++. Це жахливо і так відкрито до зловживань. Використовуйте std :: bitset
Martin York

5
Фу std::bitset, справді? Зрозуміло, замість того, щоб робити невелику роботу (і, можливо, справді хороші шаблони), щоб перевірити один біт, використовуйте роздутий контейнер, який зберігає (на мою реалізацію) кожен "біт" в іншому випадку, що не використовується unsigned long. Яка трата місця!
підкреслюй_

86

Перевірте, чи встановлено біт N (починаючи з 0):

temp & (1 << N)

Для цього немає вбудованої функції.


16
+1, щоб згадати, що він починається з 0, оскільки я підозрюю, що ОП думала на основі 1, і прийнята відповідь призведе до неприємностей. :)
Джим Бак

Гм. Чому це починається від 0? Що ми отримуємо, коли 1 << 0?? Вибачте, плутайте.
Даніель

6
Добре, зрозумів. Ми починаємо з 0-ї можливості, 1<<0тобто 1, без будь-якої зміни (зміна 0), що є1<<0 == 1
Даніель

27

Я просто використовую std :: bitset, якщо це C ++. Простий. Прямо вперед. Нема шансів на дурні помилки.

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

або як щодо цієї дурості

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 Я думаю, що ти мав на увазі std :: bitset <8 * sizeof (int)>
iNFINITEi

або std :: numeric_limits <int> :: цифри
Léo Lam

@iNFINITEi, std::bitset<CHAR_BIT * sizeof(int)>щоб бути ще правильнішим
Xeverous

13

Так, я знаю, що я не маю цього робити. Але я зазвичай пишу:

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

Наприклад:

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

Серед іншого, такий підхід:

  • Містить цілі числа 8/16/32/64.
  • Виявляє дзвінки IsBitSet (int32, int64) без мого відома та згоди.
  • Вбудований шаблон, тому жодна функція не викликає накладні витрати.
  • const & reference, тому нічого не потрібно копіювати / копіювати. І ми гарантуємо, що компілятор підбере будь-які друкарські помилки, які намагаються змінити аргументи.
  • 0! = Робить код більш чітким і очевидним. Основним моментом написання коду є завжди чітке та ефективне спілкування з іншими програмістами, у тому числі з меншими вміннями.
  • Хоча це не стосується конкретного випадку ... Загалом, шаблонні функції уникають питання оцінки аргументів кілька разів. Відома проблема деяких макросів #define.
    Наприклад: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

13

Те, що робить обрана відповідь, насправді неправильне. Наведена нижче функція повертає бітове положення або 0 залежно від того, чи справді біт увімкнено. Це не те, що просив плакат.

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

Ось що спочатку шукав плакат. Наведена нижче функція повертає або 1, або 0, якщо біт увімкнено, а не положення.

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

1
Минув деякий час, поки я зрозумів, що ти маєш на увазі. Точніше: перша функція повертає 2 до потужності бітової позиції, якщо біт встановлений, 0 в іншому випадку.
lukasl1991

1
Це якраз проблема, з якою я стикався під час її використання, як bool has_feature = CHECK_BIT(register, 25);добре знати, що я можу це зробити без подвійного заперечення.
Jimmio92

11

Згідно з цим описом бітових полів існує метод визначення та доступу до полів безпосередньо. Приклад цього запису:

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

Також є попередження:

Однак бітові члени в структурах мають практичні недоліки. По-перше, впорядкування бітів у пам'яті залежить від архітектури, і правила прокладки пам’яті змінюються від компілятора до компілятора. Крім того, багато популярних компіляторів генерують неефективний код для читання та запису бітових членів, і є потенційно серйозні проблеми безпеки потоку, пов’язані з бітовими полями (особливо у багатопроцесорних системах) через те, що більшість машин не може маніпулювати довільними наборами бітів у пам'яті, але замість цього потрібно завантажувати і зберігати цілі слова.



5

Використовуйте 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
Тут слід згадати пару речей - біти [3] дадуть вам 4-й біт - підрахунок від LSB до MSB. Якщо говорити вільно, це дасть вам 4-розрядний підрахунок справа наліво. Також sizeof (int) дає кількість символів в int, тому потрібно буде std :: bitset <sizeof (int) * CHAR_BITS> біти (temp) та біти [sizeof (int) * CHAR_BITS - 3] перевірити підрахунок третього біта від MSB до LSB, що, мабуть, є наміром.
пластик Кріс

2
Так, але я думаю, що запитуючий (а також люди, які приїжджають із пошукових запитів Google), може не мати цієї навички, і ваша відповідь може ввести їх в оману.
пластик Кріс

Ця відповідь жахлива. Його слід видалити.
Адам Беррі

Чи не tempслід відображати значення, щоб зробити його "великим-ендіаном"?
jww

4

Існує, а саме, _бітта внутрішня інструкція.


3
Посилання вказує на "Microsoft Specific". Використовуйте його лише в тому випадку, якщо вам не потрібно, щоб ваш код був портативний.
mouviciel

Посилання вказує на "Microsoft Specific", але це невід'ємна характеристика, взята з компілятора Intel C ++, і це призводить до інструкції BT, тож ви можете робити це і за допомогою вбудованого асемблера. Звичайно, це не робить його більш портативним.
Дейв Ван ден Ейнде

1
Це також характерно для архітектури x86. Так ні, точно не портативний.
jalf

Я впевнений, що інші архітектури мають подібні варіанти.
Дейв Ван ден Ейнде

Сама суть в тому, що вони користуються обладнанням, якщо воно існує, і використовують заміну програмного забезпечення, якщо апаратне забезпечення не обробляє його.
Затемнення

4

Я використовую це:

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

де "pos" визначається як 2 ^ n (ig 1,2,4,8,16,32 ...)

Повертає: 1, якщо вірно 0, якщо помилково


2
Я думаю, що це єдина правильна відповідь і для C, і для C ++. Це єдиний, хто дотримується вимоги "... без зміщення бітів і маскування" . Вам, мабуть, слід прямо вказати використання 4 = 2^(3-1)для бітової позиції 3, оскільки це було частиною питання.
jww

3

я намагався прочитати 32-бітове ціле число, яке визначило прапори для об'єкта в PDF-файлах, і це не працювало для мене

що було виправлено, це змінило визначення:

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

операнд і повертає ціле число з прапорами, які мають обоє в 1, і він не був належним чином вкинутий в булевий, це зробило трюк


!= 0зробив би те саме. Не знаю, чим можуть відрізнятися створені інструкції машини.
Адам Беррі

2

Ви можете "імітувати" зсув та маскування: якщо ((0x5e / (2 * 2 * 2))% 2) ...


Ми могли б сортувати список, випадковим чином переміщуючи його і тестуючи, чи не в даний час він "відсортований". Напр .: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Але ми не ...
Mr.Ree

Це рішення надзвичайно марнотратне на ресурси та неінтуїтивне. divs, muls та mods - це три найдорожчі функції. за допомогою тестів порівняння, а також зміни та зрушення є одними з найдешевших - деякі з небагатьох, які ви насправді зможете зробити за менш ніж 5 циклів.
jheriko

Це може бути (а це не так, тому що сучасні процесори деструюють біти та стрибки). ОР спочатку прямо попросила рішення "без зміщення бітів і маскування". Тож продовжуйте і дайте більше негативних балів за відповідність, але повільну відповідь. Я не видаляю посаду лише тому, що ОП передумав.
Леонідас

Це виглядає хитро. Давайте не будемо голосувати за цю відповідь. Іноді добре вивчити інші погляди.
В'єт

2

Для конкретного рішення низького рівня x86 використовуйте кодекс x86 TEST .

Ваш компілятор повинен перетворити _bittest у це, хоча ...


Я вважаю за краще BT над TEST, оскільки BT краще відповідає завданням.
u_Ltd.

1

Чому б не використати щось таке просте, як це?

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

ВИХІД: двійковий: 11111111


якщо ще можна зробити легко з потрійним: std::cout << (((status & (1 << i)) ? '1' : '0');. Ви повинні використовувати CHAR_BITконстанту <climits>замість жорсткого кодування 8 біт, хоча в цьому випадку ви знаєте, що результат все одно буде 8, оскільки ви використовуєтеuint8_t
Ryan Haining

0

якщо ви просто хочете справжній жорсткий спосіб:

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

Зверніть увагу на цю hw залежну і передбачає, що це біт порядку 7654 3210, а var - 8 біт.

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

Призводить до:

1 0 1 0


1
Операція & робиться на значеннях, не на внутрішньому представленні.
Remo.D

Привіт Remo.D - Не впевнений, що я розумію твій коментар? У мене є якийсь код "c", який працює чудово.
симон

Його сенс полягає в тому, що це не залежить від апаратури - IS_BIT3_SET завжди перевірятиме четвертий найменш значимий біт
Eclipse

0

Незважаючи на те, що зараз відповісти вже досить пізно, існує простий спосіб встановити, чи N-біт встановлений чи ні, просто використовуючи математичні оператори POWER та MODULUS.

Скажімо, ми хочемо знати, чи не встановлено 'temp' N-й біт чи ні. Наступний булевий вираз буде істинним, якщо встановлено біт, 0 інакше.

  • (темп. МОДУЛЬ 2 ^ N + 1> = 2 ^ N)

Розглянемо наступний приклад:

  • int temp = 0x5E; // у двійковому 0b1011110 // BIT 0 - LSB

Якщо я хочу знати, встановлений чи ні 3-й біт, я отримую

  • (94 МОДУЛЬ 16) = 14> 2 ^ 3

Таким чином, вираз повертає істину, вказуючи на встановлення 3-го біта.


0

Одним із підходів буде перевірка у наступній умові:

if ( (mask >> bit ) & 1)

Програма роз’яснення буде:

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

Вихід:

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 - позиція бітів, що відзначається від 0.

повертає 0 або 1.



Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.