C / C ++ kiểm tra xem một bit có được đặt trong hay không, tức là biến int


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

Có cách nào như vậy để kiểm tra xem bit 3 trong nhiệt độ là 1 hay 0 mà không cần dịch chuyển bit và che dấu.

Chỉ muốn biết liệu có một số chức năng được tích hợp sẵn cho việc này không, hay tôi buộc phải tự viết một cái.

Câu trả lời:


157

Trong C, nếu bạn muốn ẩn thao tác bit, bạn có thể viết macro:

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

và sử dụng nó theo cách này để kiểm tra bit thứ n từ đầu bên phải:

CHECK_BIT(temp, n - 1)

Trong C ++, bạn có thể sử dụng std :: bitset .


3
Trong trường hợp bạn cần một giá trị chân lý đơn giản, nó phải là !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu

10
@Eduard: trong C, mọi thứ đều != 0đúng, vậy tại sao phải bận tâm? 1là chính xác như sự thật 0.1415!
Christoph

1
Và trong trường hợp bạn đang sử dụng C ++, bạn có thể (nên) viết một mẫu thay vì macro. :)
jalf

2
Ở C cái này ổn. Nhưng loại macro này trong C ++. Điều đó thật kinh khủng và rất dễ bị lạm dụng. Sử dụng std :: bitset
Martin York

5
Ugh std::bitset, thật không? Chắc chắn, thay vì thực hiện một chút công việc nhỏ (và có khả năng là một số mẫu thực sự đẹp) để kiểm tra một chút, hãy sử dụng một bộ chứa cồng kềnh lưu trữ (trong phần triển khai của tôi) từng 'bit' trong một không sử dụng unsigned long. Thật là lãng phí không gian!
underscore_d

86

Kiểm tra xem bit N (bắt đầu từ 0) đã được đặt chưa:

temp & (1 << N)

Không có chức năng nội trang cho việc này.


16
+1 vì đề cập đến nó bắt đầu từ 0 vì tôi nghi ngờ OP đã suy nghĩ dựa trên 1 và câu trả lời được chấp nhận sẽ khiến anh ta gặp rắc rối. :)
Jim Buck

Hừm. Tại sao điều này lại bắt đầu từ 0? Chúng ta nhận được gì khi 1 << 0?? Xin lỗi, nhầm lẫn.
Danijel

6
OK đã nhận nó. Chúng tôi bắt đầu từ sở hữu thứ 0 1<<0, tức là số 1 không có bất kỳ sự thay đổi nào (ca 0), đó là1<<0 == 1
Danijel

27

Tôi sẽ chỉ sử dụng std :: bitset nếu đó là C ++. Đơn giản. Nói thẳng. Không có cơ hội cho những lỗi ngu ngốc.

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

hoặc làm thế nào về sự ngốc nghếch này

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 Tôi đoán u có nghĩa là std :: bitset <8 * sizeof (int)>
iNFINITEi

hoặc std :: numeric_limits <int> ::
architects

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>thậm chí còn đúng hơn
Xeverous

13

Vâng, tôi biết tôi không "phải" làm theo cách này. Nhưng tôi thường viết:

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

Ví dụ:

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

Trong số những thứ khác, cách tiếp cận này:

  • Chứa 8/16/32/64 số nguyên bit.
  • Phát hiện các cuộc gọi IsBitSet (int32, int64) mà tôi không biết và đồng ý.
  • Mẫu nội tuyến, vì vậy không có chức năng gọi chi phí.
  • const & reference, vì vậy không cần phải sao chép / sao chép. Và chúng tôi đảm bảo rằng trình biên dịch sẽ chọn bất kỳ lỗi đánh máy nào để cố gắng thay đổi các đối số.
  • 0! = Làm cho mã rõ ràng và rõ ràng hơn. Điểm chính để viết mã là luôn giao tiếp rõ ràng và hiệu quả với các lập trình viên khác, kể cả những người có kỹ năng thấp hơn.
  • Mặc dù không áp dụng cho trường hợp cụ thể này ... Nói chung, các hàm mẫu tránh vấn đề đánh giá các đối số nhiều lần. Sự cố đã biết với một số macro #define.
    Vd: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

13

Những gì câu trả lời đã chọn đang làm thực sự là sai. Hàm dưới đây sẽ trả về vị trí bit hoặc 0 tùy thuộc vào việc bit có thực sự được bật hay không. Đây không phải là những gì người đăng yêu cầu.

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

Đây là những gì người đăng ban đầu đang tìm kiếm. Hàm dưới đây sẽ trả về 1 hoặc 0 nếu bit được bật chứ không phải vị trí.

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

1
Phải mất một thời gian cho đến khi tôi hiểu ý bạn. Chính xác hơn: Hàm đầu tiên trả về 2 lũy thừa của vị trí bit nếu bit được đặt, nếu không.
lukasl1991

1
Đây là vấn đề chính xác mà tôi vừa gặp phải khi sử dụng nó như bool has_feature = CHECK_BIT(register, 25);Good to know Tôi có thể làm điều đó mà không cần phủ nhận kép.
Jimmio92

11

Theo mô tả này về trường bit , có một phương pháp để xác định và truy cập trực tiếp các trường. Ví dụ trong mục này là:

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

Ngoài ra, có một cảnh báo ở đó:

Tuy nhiên, các thành viên bit trong cấu trúc có những hạn chế thực tế. Đầu tiên, thứ tự các bit trong bộ nhớ phụ thuộc vào kiến ​​trúc và các quy tắc đệm bộ nhớ khác nhau giữa các trình biên dịch. Ngoài ra, nhiều trình biên dịch phổ biến tạo ra mã không hiệu quả để đọc và ghi các thành viên bit và có khả năng xảy ra các vấn đề nghiêm trọng về an toàn luồng liên quan đến các trường bit (đặc biệt là trên các hệ thống đa xử lý) do hầu hết các máy không thể thao tác các bộ bit tùy ý trong bộ nhớ, nhưng thay vào đó phải tải và lưu trữ toàn bộ từ.



5

Sử dụng 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
Một số điều đáng nói ở đây - bit [3] sẽ cung cấp cho bạn bit thứ 4 - tính từ LSB đến MSB. Nói một cách lỏng lẻo, nó sẽ cung cấp cho bạn 4 bit đếm từ phải sang trái. Ngoài ra, sizeof (int) cung cấp số ký tự trong một int, vì vậy nó sẽ cần phải là std :: bitset <sizeof (int) * CHAR_BITS> bits (temp) và bits [sizeof (int) * CHAR_BITS - 3] để kiểm tra việc đếm bit thứ 3 từ MSB đến LSB, đó có thể là mục đích.
chris nhựa

2
Có, nhưng tôi nghĩ người hỏi (và những người đến từ các tìm kiếm trên google) có thể không có kỹ năng đó và câu trả lời của bạn có thể đánh lừa họ.
nhựa chris

Câu trả lời này thật khủng khiếp. Nó nên được xóa.
Adam Burry

Giá trị không tempcần phải được phản ánh để làm cho nó trở thành "big-endian"?
jww

4

Có, cụ thể là hướng dẫn nội tại _bittest .


3
Liên kết cho biết "Microsoft Cụ thể". Chỉ sử dụng nó nếu bạn không cần mã di động.
mouviciel 07/02/09

Liên kết cho biết "Cụ thể của Microsoft", nhưng nó là nội tại được tiếp quản từ trình biên dịch Intel C ++ và nó dẫn đến một lệnh BT, vì vậy bạn cũng có thể làm điều đó với trình hợp dịch nội tuyến. Tất nhiên, điều đó không làm cho nó dễ di chuyển hơn.
Dave Van den Eynde 07/02/09

1
Nó cũng dành riêng cho kiến ​​trúc x86. Vì vậy, không, chắc chắn không phải là hàng xách tay.
jalf

Tôi chắc rằng các kiến ​​trúc khác cũng có những lựa chọn tương tự.
Dave Van den Eynde 07/02/09

Điểm mấu chốt của bản chất là họ tận dụng phần cứng nếu nó tồn tại và sử dụng phần mềm thay thế nếu phần cứng không xử lý được.
Nhật thực

4

Tôi sử dụng cái này:

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

trong đó "pos" được định nghĩa là 2 ^ n (tức là 1,2,4,8,16,32 ...)

Trả về: 1 nếu đúng 0 nếu sai


2
Tôi nghĩ đây là câu trả lời đúng duy nhất cho cả C và C ++. Nó là người duy nhất tôn trọng yêu cầu "... không có bit thay đổi và che" . Bạn có thể nên nêu rõ ràng để sử dụng 4 = 2^(3-1)cho vị trí bit 3 vì nó là một phần của câu hỏi.
jww

3

tôi đang cố đọc một số nguyên 32 bit xác định các cờ cho một đối tượng trong tệp PDF và điều này không hiệu quả với tôi

điều gì đã sửa nó đã thay đổi định nghĩa:

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

toán hạng & trả về một số nguyên với các cờ đều có trong 1 và nó không được truyền đúng cách thành boolean, điều này đã thực hiện một mẹo nhỏ


!= 0cũng sẽ làm như vậy. Không biết các hướng dẫn máy đã tạo có thể khác nhau như thế nào.
Adam Burry

2

Bạn có thể "mô phỏng" dịch chuyển và che: if ((0x5e / (2 * 2 * 2))% 2) ...


Chúng tôi có thể sắp xếp một danh sách bằng cách xáo trộn ngẫu nhiên nó và thử nghiệm xem liệu bây giờ nó đã được "sắp xếp" hay chưa. Vd: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Nhưng chúng tôi không ...
Mr.Ree

Giải pháp này cực kỳ lãng phí tài nguyên và không trực quan. divs, muls và mod là ba hàm đắt tiền nhất. bằng các bài kiểm tra so sánh, ands và shift là một trong những mức rẻ nhất - một số trong số ít bạn có thể thực sự hoàn thành trong vòng chưa đầy 5 chu kỳ.
jheriko 09/02/09

Điều đó có thể là (và không, bởi vì các bộ xử lý hiện đại ghét các bit và bước nhảy). OP ban đầu đã yêu cầu rõ ràng một giải pháp "không có sự dịch chuyển bit và che khuất." Vì vậy, hãy tiếp tục và đưa ra nhiều điểm tiêu cực hơn cho một câu trả lời phù hợp nhưng chậm. Tôi sẽ không xóa bài viết chỉ vì OP đã thay đổi ý định.
Leonidas 09/02/09

Nó trông phức tạp. Chúng ta đừng bỏ phiếu cho câu trả lời này. Đôi khi, thật tốt khi khám phá các góc nhìn khác.
Việt

2

Đối với giải pháp cụ thể x86 cấp thấp, hãy sử dụng mã opcode x86 TEST .

Tuy nhiên, trình biên dịch của bạn nên biến _bittest thành ...


Tôi muốn BT hơn TEST vì BT phù hợp với nhiệm vụ theo cách tốt hơn.
u_Ltd.

1

Tại sao không sử dụng một cái gì đó đơn giản như thế này?

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

ĐẦU RA: nhị phân: 11111111


nếu ai có thể được thực hiện một cách dễ dàng với một ternary: std::cout << (((status & (1 << i)) ? '1' : '0');. Bạn nên sử dụng CHAR_BITliên tục từ <climits>thay vì cứng mã hóa 8 bit, mặc dù trong trường hợp này bạn biết kết quả sẽ là 8 nào kể từ khi bạn đang sử dụng mộtuint8_t
Ryan Haining

0

nếu bạn chỉ muốn một cách mã hóa cứng thực sự:

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

lưu ý điều này phụ thuộc vào hw và giả sử thứ tự bit này 7654 3210 và var là 8 bit.

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

Kết quả trong:

1 0 1 0


1
Thao tác & được thực hiện trên các giá trị không có trên biểu diễn nội bộ.
Remo.D

Xin chào Remo.D - Tôi không chắc tôi hiểu nhận xét của bạn? Tôi đã bao gồm một số mã 'c' hoạt động tốt.
simon

Quan điểm của anh ấy là nó không phụ thuộc vào phần cứng - IS_BIT3_SET sẽ luôn kiểm tra bit quan trọng thứ 4
Eclipse

0

Mặc dù bây giờ đã khá muộn để trả lời, nhưng có một cách đơn giản mà người ta có thể tìm xem bit thứ N có được đặt hay không, chỉ cần sử dụng các toán tử toán học POWER và MODULUS.

Giả sử chúng tôi muốn biết liệu 'temp' có đặt bit thứ N hay không. Biểu thức boolean sau sẽ cho true nếu bit được đặt, ngược lại là 0.

  • (tạm thời MODULUS 2 ^ N + 1> = 2 ^ N)

Hãy xem xét ví dụ sau:

  • int temp = 0x5E; // trong hệ nhị phân 0b1011110 // BIT 0 là LSB

Nếu tôi muốn biết liệu bit thứ 3 có được đặt hay không, tôi nhận được

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

Vì vậy, biểu thức trả về true, cho biết bit thứ 3 được thiết lập.


0

Một cách tiếp cận sẽ được kiểm tra trong điều kiện sau:

if ( (mask >> bit ) & 1)

Một chương trình giải thích sẽ là:

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

Đầu ra:

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 - Phân tầng vị trí bit từ 0.

trả về 0 hoặc 1.


-1

Tôi làm nó:

LATGbits.LATG0 = ((m & 0x8)> 0); // để kiểm tra xem bit-2 của m có phải là 1 hay không


-2

cách nhanh nhất dường như là bảng tra cứu mặt nạ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.