C / C ++ проверяет, установлен ли один бит, т.е. переменная int


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

Есть ли способ проверить, равен ли бит 3 в temp 1 или 0 без сдвига бит и маскирования.

Просто хочу знать, есть ли для этого какая-то встроенная функция, или я вынужден написать ее сам.

Ответы:


160

В C, если вы хотите скрыть манипуляции с битами, вы можете написать макрос:

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

и используйте его таким образом, чтобы проверить n- й бит с правого конца:

CHECK_BIT(temp, n - 1)

В C ++ вы можете использовать std :: bitset .


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

10
@ Эдуард: в C все != 0верно, так зачем? 1точно так же верно, как 0.1415!
Кристоф,

1
А если вы используете C ++, вы можете (должны) написать шаблон вместо макроса. :)
jalf

2
В C это нормально. Но это своего рода макросы в C ++. Это ужасно и открыто для злоупотреблений. Use std :: bitset
Мартин Йорк,

1
но битсет должен знать размер во время компиляции
graywolf 07

87

Проверьте, установлен ли бит N (начиная с 0):

temp & (1 << N)

Для этого нет встроенной функции.


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

Хм. Почему это начинается с 0? Что мы получим когда 1 << 0?? Простите, запуталась.
Даниэль

6
Хорошо понял. Мы начинаем с 0-й позиции, которая равна 1<<01 без какой-либо смены (смена 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> :: digits
Лео Лам,

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

14

Да, я знаю, что мне «не нужно» делать это таким образом. Но я обычно пишу:

    /* 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 & ссылки, поэтому ничего не нужно дублировать / копировать. И мы гарантируем, что компилятор уловит любую опечатку, пытающуюся изменить аргументы.
  • 0! = Делает код более понятным и очевидным. Первоочередной задачей при написании кода всегда является четкое и эффективное общение с другими программистами, в том числе с менее опытными.
  • Хотя это и не применимо к этому конкретному случаю ... В общем, шаблонные функции позволяют избежать многократной оценки аргументов. Известная проблема с некоторыми макросами #define.
    Например: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

14

На самом деле выбранный ответ неверен. Приведенная ниже функция вернет битовую позицию или 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> bits (temp) и bits [sizeof (int) * CHAR_BITS - 3] чтобы проверить счет 3-го бита от MSB до LSB, что, вероятно, и является целью.
пластиковый Крис

2
Да, но я думаю, что у спрашивающего (и людей, которые ищут в Google) может не быть этого навыка, и ваш ответ может ввести их в заблуждение.
пластиковый Крис

Это ужасный ответ. Его следует удалить.
Адам Берри

Разве значение не tempнужно отражать, чтобы сделать его "прямым порядком"?
jww 09

4

Есть, а именно внутренняя инструкция _bittest .


3
Ссылка указывает на «Microsoft Specific». Используйте его только в том случае, если вам не нужен переносимый код.
mouviciel

Ссылка указывает на «Microsoft Specific», но это внутренняя функция компилятора Intel C ++, которая приводит к инструкции BT, так что вы также можете сделать это с помощью встроенного ассемблера. Конечно, это не делает его более портативным.
Дэйв Ван ден Эйнде,

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

Я уверен, что у других архитектур есть аналогичные возможности.
Дэйв Ван ден Эйнде,

Сама суть встроенных функций состоит в том, что они используют преимущества оборудования, если оно существует, и заменяют программное обеспечение, если оборудование не справляется с этим.
Eclipse,

4

Я использую это:

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

где "pos" определяется как 2 ^ n (например, 1,2,4,8,16,32 ...)

Возвращает: 1, если истина 0, если ложь


2
Я думаю, что это единственно правильный ответ как для C, так и для C ++. Это единственный, который соблюдает требование «... без сдвига битов и маскирования» . Вероятно, вам следует явно указать, что нужно использовать 4 = 2^(3-1)для битовой позиции 3, поскольку это было частью вопроса.
jww 09

3

Я пытался прочитать 32-битное целое число, которое определяло флаги для объекта в PDF-файлах, и это не сработало для меня

что исправлено, это изменяло определение:

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

операнд & возвращает целое число с флагами, которые оба имеют в 1, и он неправильно переводился в логическое значение, это помогло


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

2

Вы можете «имитировать» сдвиг и маскировку: if ((0x5e / (2 * 2 * 2))% 2) ...


Мы могли бы отсортировать список, перемешивая его случайным образом и проверяя, «отсортирован ли он». Например: while (/ * НЕ * /! IsSorted ()) {RandomlyShuffle (); } Но мы не ...
Мистер Ри,

Это решение чрезвычайно затратно по ресурсам и не интуитивно понятно. div, muls и mods - три самые дорогие функции. Судя по сравнительным тестам, операции и сдвиги являются одними из самых дешевых - некоторые из немногих, которые можно выполнить менее чем за 5 циклов.
jheriko

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

Смотрится сложно. Не будем отклонять этот ответ. Иногда полезно изучить другие взгляды.
Viet

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
Райан Хейнинг


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 07

Привет Remo.D - Не уверен, что понимаю ваш комментарий? Я добавил код 'c', который отлично работает.
Саймон

Его точка зрения заключается в том, что это не зависит от оборудования - IS_BIT3_SET всегда будет проверять 4-й младший значащий бит
Eclipse

0

Хотя сейчас уже довольно поздно отвечать, есть простой способ узнать, установлен ли N-й бит или нет, просто используя математические операторы POWER и MODULUS.

Допустим, мы хотим знать, установлен ли у 'temp' N-й бит или нет. Следующее логическое выражение вернет истину, если бит установлен, в противном случае - 0.

  • (темп MODULUS 2 ^ N + 1> = 2 ^ N)

Рассмотрим следующий пример:

  • int temp = 0x5E; // в двоичном формате 0b1011110 // BIT 0 - это LSB

Если я хочу знать, установлен ли 3-й бит или нет, я получаю

  • (94 МОДУЛЬ 16) = 14> 2 ^ 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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.