Làm thế nào để bạn thiết lập, xóa và chuyển đổi một chút?

2676
JeffV 2008-09-07 14:42.

Làm thế nào để bạn thiết lập, rõ ràng và chuyển đổi một chút?

28 answers

3724
Jeremy Ruten 2008-09-07 14:50.

Thiết lập một chút

Sử dụng toán tử OR bitwise ( |) để đặt một bit.

number |= 1UL << n;

Điều đó sẽ thiết lập nbit thứ của number. nphải bằng 0, nếu bạn muốn đặt 1bit thứ và tương tự như vậy n-1, nếu bạn muốn đặt nbit thứ.

Sử dụng 1ULLif numberrộng hơn unsigned long; quảng cáo của 1UL << nkhông xảy ra cho đến khi đánh giá 1UL << nvị trí mà hành vi không xác định của nó sẽ thay đổi nhiều hơn chiều rộng của a long. Điều tương tự cũng áp dụng cho tất cả các ví dụ còn lại.

Giải tỏa một chút

Sử dụng toán tử AND bitwise ( &) để xóa một chút.

number &= ~(1UL << n);

Điều đó sẽ xóa nbit thứ của number. Bạn phải đảo ngược chuỗi bit bằng toán tử NOT ( ~) theo bitwise , sau đó AND nó.

Chuyển đổi một chút

Toán tử XOR ( ^) có thể được sử dụng để chuyển đổi một chút.

number ^= 1UL << n;

Điều đó sẽ chuyển đổi nbit thứ của number.

Kiểm tra một chút

Bạn không yêu cầu điều này, nhưng tôi cũng có thể thêm nó.

Để kiểm tra một chút, hãy chuyển số n sang phải, sau đó theo chiều kim bit VÀ nó:

bit = (number >> n) & 1U;

Điều đó sẽ đặt giá trị của nbit thứ của numbervào biến bit.

Thay đổi bit thứ n thành x

Đặt nbit thứ thành một trong hai 1hoặc 0có thể đạt được bằng cách sau khi triển khai C ++ bổ sung của 2:

number ^= (-x ^ number) & (1UL << n);

Bit nsẽ được đặt nếu x1và bị xóa nếu x0. Nếu xcó một số giá trị khác, bạn sẽ nhận được rác. x = !!xsẽ booleanize nó thành 0 hoặc 1.

Để làm cho điều này độc lập với hành vi phủ định phần bổ sung của 2 (nơi -1đã đặt tất cả các bit, không giống như phần bổ sung của 1 hoặc triển khai dấu / độ lớn C ++), hãy sử dụng phủ định không dấu.

number ^= (-(unsigned long)x ^ number) & (1UL << n);

hoặc là

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

Nói chung, bạn nên sử dụng các kiểu không dấu cho thao tác bit di động.

hoặc là

number = (number & ~(1UL << n)) | (x << n);

(number & ~(1UL << n))sẽ xóa nbit thứ và (x << n)sẽ đặt nbit thứ thành x.

Nói chung, bạn không nên sao chép / dán mã nói chung và vì vậy nhiều người sử dụng macro bộ xử lý trước (như câu trả lời của wiki cộng đồng ) hoặc một số loại đóng gói.

471
Martin York 2008-09-18 14:34.

Sử dụng bộ thư viện chuẩn C ++: std::bitset<N>.

Hoặc Boost phiên bản: boost::dynamic_bitset.

Không cần phải cuộn của riêng bạn:

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<5> x;

    x[1] = 1;
    x[2] = 0;
    // Note x[0-4]  valid

    std::cout << x << std::endl;
}

[Alpha:] > ./a.out
00010

Phiên bản Boost cho phép tập hợp bit có kích thước thời gian chạy so với tập hợp bit có kích thước thời gian biên dịch thư viện tiêu chuẩn .

254
Ferruccio 2008-09-11 14:56.

Tùy chọn khác là sử dụng các trường bit:

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

xác định trường 3-bit (thực tế, đó là ba trường 1-bit). Các thao tác trên bit giờ trở nên đơn giản hơn một chút (haha):

Để thiết lập hoặc xóa một chút:

mybits.b = 1;
mybits.c = 0;

Để chuyển đổi một chút:

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

Kiểm tra một chút:

if (mybits.c)  //if mybits.c is non zero the next line below will execute

Điều này chỉ hoạt động với các trường bit có kích thước cố định. Nếu không, bạn phải sử dụng các kỹ thuật xoay bit được mô tả trong các bài viết trước.

193
Steve Karg 2008-11-05 12:35.

Tôi sử dụng macro được xác định trong tệp tiêu đề để xử lý tập hợp bit và xóa:

/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b))))        // '!!' to make sure this returns 0 or 1

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (!(~(x) & (y)))
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))
119

Đôi khi nên sử dụng một enumđể đặt tên cho các bit:

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

Sau đó sử dụng các tên sau này. Tức là viết

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

để thiết lập, rõ ràng và kiểm tra. Bằng cách này, bạn ẩn các con số kỳ diệu khỏi phần còn lại của mã của bạn.

Ngoài ra, tôi tán thành giải pháp của Jeremy.

49
yogeesh 2008-09-17 16:04.

Từ bitops.h của snip-c.zip:

/*
**  Bit set, clear, and test operations
**
**  public domain snippet by Bob Stout
*/

typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

OK, chúng ta hãy phân tích mọi thứ ...

Biểu thức phổ biến mà bạn có vẻ đang gặp vấn đề trong tất cả những điều này là "(1L << (posn))". Tất cả những việc này là tạo một mặt nạ với một bit duy nhất được bật và sẽ hoạt động với bất kỳ kiểu số nguyên nào. Đối số "posn" chỉ định vị trí mà bạn muốn bit. Nếu posn == 0, thì biểu thức này sẽ đánh giá thành:

0000 0000 0000 0000 0000 0000 0000 0001 binary.

Nếu posn == 8, nó sẽ đánh giá là:

0000 0000 0000 0000 0000 0001 0000 0000 binary.

Nói cách khác, nó chỉ đơn giản tạo ra một trường của 0 với 1 tại vị trí được chỉ định. Phần khó khăn duy nhất là trong macro BitClr (), nơi chúng ta cần đặt một bit 0 duy nhất trong trường của 1. Điều này được thực hiện bằng cách sử dụng phần bù 1 của cùng một biểu thức như được biểu thị bằng toán tử dấu ngã (~).

Khi mặt nạ được tạo, nó được áp dụng cho đối số giống như bạn đề xuất, bằng cách sử dụng các toán tử bitwise và (&), hoặc (|) và xor (^). Vì mặt nạ thuộc loại dài, các macro sẽ hoạt động tốt trên các ký tự char, short, int hoặc long.

Điểm mấu chốt là đây là một giải pháp chung cho toàn bộ các vấn đề. Tất nhiên, có thể và thậm chí thích hợp để viết lại tương đương của bất kỳ macro nào trong số này với các giá trị mặt nạ rõ ràng mỗi khi bạn cần, nhưng tại sao lại làm như vậy? Hãy nhớ rằng, thay thế macro xảy ra trong bộ tiền xử lý và do đó mã được tạo sẽ phản ánh thực tế là các giá trị được trình biên dịch coi là không đổi - tức là sử dụng macro tổng quát cũng hiệu quả như để "phát minh lại bánh xe" mỗi khi bạn cần thực hiện thao tác bit.

Không thuyết phục? Đây là một số mã thử nghiệm - Tôi đã sử dụng Watcom C với tối ưu hóa hoàn toàn và không sử dụng _cdecl để kết quả tháo gỡ sẽ sạch nhất có thể:

---- [TEST.C] ----------------------------------------- -----------------------

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

int bitmanip(int word)
{
      word = BitSet(word, 2);
      word = BitSet(word, 7);
      word = BitClr(word, 3);
      word = BitFlp(word, 9);
      return word;
}

---- [TEST.OUT (đã tháo rời)] -------------------------------------- ---------

Module: C:\BINK\tst.c
Group: 'DGROUP' CONST,CONST2,_DATA,_BSS

Segment: _TEXT  BYTE   00000008 bytes  
 0000  0c 84             bitmanip_       or      al,84H    ; set bits 2 and 7
 0002  80 f4 02                          xor     ah,02H    ; flip bit 9 of EAX (bit 1 of AH)
 0005  24 f7                             and     al,0f7H
 0007  c3                                ret     

No disassembly errors

---- [hoàn thành] ------------------------------------------- ----------------------

39
nsanders 2008-09-07 14:45.

Sử dụng các toán tử bitwise: & |

Để đặt bit cuối cùng trong 000b:

foo = foo | 001b

Để kiểm tra bit cuối cùng trong foo:

if ( foo & 001b ) ....

Để xóa bit cuối cùng trong foo:

foo = foo & 110b

Tôi đã sử dụng XXXbcho rõ ràng. Có thể bạn sẽ làm việc với biểu diễn HEX, tùy thuộc vào cấu trúc dữ liệu mà bạn đang đóng gói các bit.

35
kapilddit 2012-06-06 04:18.

Đối với người mới bắt đầu, tôi muốn giải thích thêm một chút bằng một ví dụ:

Thí dụ:

value is 0x55;
bitnum : 3rd.

Các &nhà điều hành được sử dụng kiểm tra các bit:

0101 0101
&
0000 1000
___________
0000 0000 (mean 0: False). It will work fine if the third bit is 1 (then the answer will be True)

Chuyển đổi hoặc Lật:

0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)

| toán tử: đặt bit

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)
27
R.. GitHub STOP HELPING ICE 2010-07-13 20:53.

Đây là macro số học bit yêu thích của tôi, hoạt động cho bất kỳ loại mảng số nguyên không dấu nào từ unsigned chartrở lên size_t(là loại lớn nhất nên làm việc hiệu quả):

#define BITOP(a,b,op) \
 ((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))

Để thiết lập một chút:

BITOP(array, bit, |=);

Để rõ ràng một chút:

BITOP(array, bit, &=~);

Để chuyển đổi một chút:

BITOP(array, bit, ^=);

Để kiểm tra một chút:

if (BITOP(array, bit, &)) ...

Vân vân.

26
John U 2012-06-15 05:23.

Vì điều này được gắn thẻ "nhúng", tôi sẽ cho rằng bạn đang sử dụng một bộ vi điều khiển. Tất cả các đề xuất trên đều hợp lệ và hoạt động (đọc-sửa-viết, hợp nhất, cấu trúc, v.v.).

Tuy nhiên, trong quá trình gỡ lỗi dựa trên máy hiện sóng, tôi đã rất ngạc nhiên khi thấy rằng các phương pháp này có chi phí đáng kể trong các chu kỳ CPU so với việc ghi giá trị trực tiếp vào các thanh ghi PORTnSET / PORTnCLEAR của vi điều này tạo ra sự khác biệt thực sự khi có các vòng lặp chặt chẽ / cao -frequency ISR của chân chuyển đổi.

Đối với những người không quen thuộc: Trong ví dụ của tôi, vi có thanh ghi trạng thái pin chung PORTn phản ánh các chân đầu ra, do đó, thực hiện PORTn | = BIT_TO_SET dẫn đến việc đọc-sửa-ghi vào thanh ghi đó. Tuy nhiên, các thanh ghi PORTnSET / PORTnCLEAR có '1' có nghĩa là "vui lòng đặt bit này thành 1" (SET) hoặc "vui lòng đặt bit này bằng 0" (CLEAR) và '0' có nghĩa là "để nguyên ghim". vì vậy, bạn kết thúc với hai địa chỉ cổng tùy thuộc vào việc bạn đang thiết lập hay xóa bit (không phải lúc nào cũng thuận tiện) nhưng phản ứng nhanh hơn nhiều và mã được lắp ráp nhỏ hơn.

25
Roddy 2008-11-07 01:30.

Cách tiếp cận bitfield có những lợi thế khác trong lĩnh vực nhúng. Bạn có thể xác định một cấu trúc ánh xạ trực tiếp lên các bit trong một thanh ghi phần cứng cụ thể.

struct HwRegister {
    unsigned int errorFlag:1;  // one-bit flag field
    unsigned int Mode:3;       // three-bit mode field
    unsigned int StatusCode:4;  // four-bit status code
};

struct HwRegister CR3342_AReg;

Bạn cần lưu ý về thứ tự đóng gói bit - trước tiên tôi nghĩ đó là MSB, nhưng điều này có thể phụ thuộc vào việc triển khai. Ngoài ra, hãy xác minh cách các trường trình xử lý trình biên dịch của bạn vượt qua ranh giới byte.

Sau đó, bạn có thể đọc, ghi, kiểm tra các giá trị riêng lẻ như trước đây.

20
John Zwinck 2009-01-04 13:44.

Kiểm tra một chút tại một vị trí tùy ý trong một biến kiểu tùy ý:

#define bit_test(x, y)  ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

Cách sử dụng mẫu:

int main(void)
{
    unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };

    for (int ix = 0; ix < 64; ++ix)
        printf("bit %d is %d\n", ix, bit_test(arr, ix));

    return 0;
}

Lưu ý: Điều này được thiết kế để nhanh chóng (do tính linh hoạt của nó) và không phân nhánh. Nó tạo ra mã máy SPARC hiệu quả khi được biên dịch Sun Studio 8; Tôi cũng đã thử nghiệm nó bằng MSVC ++ 2008 trên amd64. Có thể tạo các macro tương tự để thiết lập và xóa các bit. Sự khác biệt chính của giải pháp này so với nhiều giải pháp khác ở đây là nó hoạt động cho bất kỳ vị trí nào trong hầu hết mọi loại biến.

20
bill 2009-06-14 11:27.

Tổng quát hơn, đối với các bitmap có kích thước tùy ý:

#define BITS 8
#define BIT_SET(  p, n) (p[(n)/BITS] |=  (0x80>>((n)%BITS)))
#define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS)))
#define BIT_ISSET(p, n) (p[(n)/BITS] &   (0x80>>((n)%BITS)))
14
Gokul Naathan 2012-02-29 09:27.

Chương trình này là để thay đổi bất kỳ bit dữ liệu nào từ 0 thành 1 hoặc 1 thành 0:

{
    unsigned int data = 0x000000F0;
    int bitpos = 4;
    int bitvalue = 1;
    unsigned int bit = data;
    bit = (bit>>bitpos)&0x00000001;
    int invbitvalue = 0x00000001&(~bitvalue);
    printf("%x\n",bit);

    if (bitvalue == 0)
    {
        if (bit == 0)
            printf("%x\n", data);
        else
        {
             data = (data^(invbitvalue<<bitpos));
             printf("%x\n", data);
        }
    }
    else
    {
        if (bit == 1)
            printf("elseif %x\n", data);
        else
        {
            data = (data|(bitvalue<<bitpos));
            printf("else %x\n", data);
        }
    }
}
12
Noname 2009-04-12 13:05.

Dùng cái này:

int ToggleNthBit ( unsigned char n, int num )
{
    if(num & (1 << n))
        num &= ~(1 << n);
    else
        num |= (1 << n);

    return num;
}
12
Tim Ring 2008-09-18 04:10.

Nếu bạn đang thực hiện nhiều thao tác lộn xộn, bạn có thể muốn sử dụng mặt nạ để làm cho mọi thứ nhanh hơn. Các chức năng sau đây rất nhanh và vẫn linh hoạt (chúng cho phép bit trong bản đồ bit ở bất kỳ kích thước nào).

const unsigned char TQuickByteMask[8] =
{
   0x01, 0x02, 0x04, 0x08,
   0x10, 0x20, 0x40, 0x80,
};


/** Set bit in any sized bit mask.
 *
 * @return    none
 *
 * @param     bit    - Bit number.
 * @param     bitmap - Pointer to bitmap.
 */
void TSetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] |= TQuickByteMask[n];        // Set bit.
}


/** Reset bit in any sized mask.
 *
 * @return  None
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TResetBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] &= (~TQuickByteMask[n]);    // Reset bit.
}


/** Toggle bit in any sized bit mask.
 *
 * @return   none
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
void TToggleBit( short bit, unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;        // Index to byte.
    n = bit % 8;        // Specific bit in byte.

    bitmap[x] ^= TQuickByteMask[n];        // Toggle bit.
}


/** Checks specified bit.
 *
 * @return  1 if bit set else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitSet( short bit, const unsigned char *bitmap)
{
    short n, x;

    x = bit / 8;    // Index to byte.
    n = bit % 8;    // Specific bit in byte.

    // Test bit (logigal AND).
    if (bitmap[x] & TQuickByteMask[n])
        return 1;

    return 0;
}


/** Checks specified bit.
 *
 * @return  1 if bit reset else 0.
 *
 * @param   bit    - Bit number.
 * @param   bitmap - Pointer to bitmap.
 */
short TIsBitReset( short bit, const unsigned char *bitmap)
{
    return TIsBitSet(bit, bitmap) ^ 1;
}


/** Count number of bits set in a bitmap.
 *
 * @return   Number of bits set.
 *
 * @param    bitmap - Pointer to bitmap.
 * @param    size   - Bitmap size (in bits).
 *
 * @note    Not very efficient in terms of execution speed. If you are doing
 *        some computationally intense stuff you may need a more complex
 *        implementation which would be faster (especially for big bitmaps).
 *        See (http://graphics.stanford.edu/~seander/bithacks.html).
 */
int TCountBits( const unsigned char *bitmap, int size)
{
    int i, count = 0;

    for (i=0; i<size; i++)
        if (TIsBitSet(i, bitmap))
            count++;

    return count;
}

Lưu ý, để đặt bit 'n' thành số nguyên 16 bit, bạn làm như sau:

TSetBit( n, &my_int);

Bạn phải đảm bảo rằng số bit nằm trong phạm vi của bản đồ bit mà bạn vượt qua. Lưu ý rằng đối với các bộ xử lý endian nhỏ mà byte, từ, dwords, qwords, v.v., ánh xạ chính xác với nhau trong bộ nhớ (lý do chính mà bộ xử lý endian nhỏ 'tốt hơn' so với bộ xử lý big end, tôi cảm thấy một cuộc chiến bùng nổ sắp xảy ra trên...).

10
kendotwill 2014-05-08 18:33.

Mở rộng bitsetcâu trả lời:

#include <iostream>
#include <bitset>
#include <string>

using namespace std;
int main() {
  bitset<8> byte(std::string("10010011");

  // Set Bit
  byte.set(3); // 10010111

  // Clear Bit
  byte.reset(2); // 10010101

  // Toggle Bit
  byte.flip(7); // 00010101

  cout << byte << endl;

  return 0;
}
10
Jeegar Patel 2016-05-28 06:41.

Nếu bạn muốn thực hiện tất cả thao tác này với lập trình C trong nhân Linux thì tôi khuyên bạn nên sử dụng các API tiêu chuẩn của nhân Linux.

Xem https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html

set_bit  Atomically set a bit in memory
clear_bit  Clears a bit in memory
change_bit  Toggle a bit in memory
test_and_set_bit  Set a bit and return its old value
test_and_clear_bit  Clear a bit and return its old value
test_and_change_bit  Change a bit and return its old value
test_bit  Determine whether a bit is set

Lưu ý: Ở đây toàn bộ hoạt động diễn ra trong một bước duy nhất. Vì vậy, tất cả những thứ này đều được đảm bảo là nguyên tử ngay cả trên máy tính SMP và rất hữu ích để giữ sự liên kết giữa các bộ xử lý.

10
Noname 2012-12-30 16:31.

Visual C 2010 và có lẽ nhiều trình biên dịch khác có hỗ trợ trực tiếp cho các hoạt động boolean được tích hợp sẵn. Một bit có hai giá trị khả dĩ, giống như boolean, vì vậy chúng ta có thể sử dụng boolean thay thế - ngay cả khi chúng chiếm nhiều dung lượng hơn một bit trong bộ nhớ trong biểu diễn này. Điều này hoạt động, ngay cả sizeof()nhà điều hành hoạt động đúng.

bool    IsGph[256], IsNotGph[256];

//  Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++)  {
    IsGph[i] = isgraph((unsigned char)i);
}

Vì vậy, đối với câu hỏi của bạn IsGph[i] =1, hoặc IsGph[i] =0làm cho việc thiết lập và xóa bools trở nên dễ dàng.

Để tìm các ký tự không in được:

//  Initialize boolean array to detect UN-printable characters, 
//  then call function to toggle required bits true, while initializing a 2nd
//  boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++)  {
    if(IsGph[i])    {
         IsNotGph[i] = 0;
    }   else   {
         IsNotGph[i] = 1;
    }
}

Lưu ý rằng không có gì "đặc biệt" về mã này. Nó xử lý một chút giống như một số nguyên - về mặt kỹ thuật, nó là như vậy. Một số nguyên 1 bit có thể chứa 2 giá trị và chỉ 2 giá trị.

Tôi đã từng sử dụng cách tiếp cận này để tìm các bản ghi khoản vay trùng lặp, trong đó loan_number là khóa ISAM, sử dụng số cho vay gồm 6 chữ số làm chỉ số cho mảng bit. Quá nhanh, và sau 8 tháng, đã chứng minh rằng hệ thống máy tính lớn mà chúng tôi đang lấy dữ liệu trên thực tế đã bị trục trặc. Tính đơn giản của các mảng bit làm cho độ tin cậy về tính đúng đắn của chúng rất cao - ví dụ như cách tiếp cận tìm kiếm.

7
Pankaj Prakash 2019-06-10 19:52.

Giả sử một số điều đầu tiên
num = 55 Integer thực hiện các phép toán bit (đặt, lấy, xóa, chuyển đổi).
n = 40 dựa trên vị trí bit để thực hiện các hoạt động bitwise.

Làm thế nào để có được một chút?

  1. Để có được nthbit của num dịch chuyển phải num, nlần. Sau đó, thực hiện theo bitwise AND &với 1.
bit = (num >> n) & 1;

Làm thế nào nó hoạt động?

       0011 0111 (55 in decimal)
    >>         4 (right shift 4 times)
-----------------
       0000 0011
     & 0000 0001 (1 in decimal)
-----------------
    => 0000 0001 (final result)

Làm thế nào để thiết lập một chút?

  1. Để đặt một số bit cụ thể. Ca trái 1 nlần. Sau đó, thực hiện thao tác theo bitwise OR |với num.
num |= (1 << n);    // Equivalent to; num = (1 << n) | num;

Làm thế nào nó hoạt động?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     | 0011 0111 (55 in decimal)
-----------------
    => 0001 0000 (final result)

Làm thế nào để giải tỏa một chút?

  1. Sang trái 1, nlần tức là 1 << n.
  2. Thực hiện bổ sung bitwise với kết quả trên. Vì vậy, bit thứ n trở nên không được đặt và phần còn lại của bit trở thành được đặt tức là ~ (1 << n).
  3. Cuối cùng, thực hiện thao tác bitwise AND &với kết quả trên và num. Ba bước trên cùng nhau có thể được viết là num & (~ (1 << n));

num &= (~(1 << n));    // Equivalent to; num = num & (~(1 << n));

Làm thế nào nó hoạt động?

       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
     ~ 0001 0000
-----------------
       1110 1111
     & 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

Làm thế nào để chuyển đổi một chút?

Để chuyển đổi một chút, chúng tôi sử dụng toán ^tử XOR bitwise . Toán tử Bitwise XOR đánh giá là 1 nếu bit tương ứng của cả hai toán hạng là khác nhau, nếu không thì đánh giá là 0.

Có nghĩa là để chuyển đổi một chút, chúng ta cần thực hiện thao tác XOR với bit bạn muốn chuyển đổi và 1.

num ^= (1 << n);    // Equivalent to; num = num ^ (1 << n);

Làm thế nào nó hoạt động?

  • Nếu bit để chuyển đổi là 0 thì 0 ^ 1 => 1,.
  • Nếu bit để chuyển đổi là 1 thì 1 ^ 1 => 0,.
       0000 0001 (1 in decimal)
    <<         4 (left shift 4 times)
-----------------
       0001 0000
     ^ 0011 0111 (55 in decimal)
-----------------
    => 0010 0111 (final result)

Đề xuất đọc - Bài tập toán tử bitwise

6
Jason 2012-04-30 20:48.

Sử dụng một trong các toán tử như được định nghĩa ở đây .

Để thiết lập một bit, được sử dụng int x = x | 0x?;ở đâu ?là vị trí bit ở dạng nhị phân.

5
sam msft 2015-02-07 13:11.

Đây là một số macro tôi sử dụng:

SET_FLAG(Status, Flag)            ((Status) |= (Flag))
CLEAR_FLAG(Status, Flag)          ((Status) &= ~(Flag))
INVALID_FLAGS(ulFlags, ulAllowed) ((ulFlags) & ~(ulAllowed))
TEST_FLAGS(t,ulMask, ulBit)       (((t)&(ulMask)) == (ulBit))
IS_FLAG_SET(t,ulMask)             TEST_FLAGS(t,ulMask,ulMask)
IS_FLAG_CLEAR(t,ulMask)           TEST_FLAGS(t,ulMask,0)
5
Jeet Parikh 2018-07-12 07:32.

Biến được sử dụng

int value, pos;

giá trị - Vị
trí dữ liệu - vị trí của bit mà chúng tôi muốn đặt, xóa hoặc chuyển đổi.

Đặt một chút:

value = value | 1 << pos;

Xóa một chút:

value = value & ~(1 << pos); 

Chuyển đổi một chút:

value = value ^ 1 << pos;
5
Sazzad Hissain Khan 2018-02-22 02:35.
int set_nth_bit(int num, int n){    
    return (num | 1 << n);
}

int clear_nth_bit(int num, int n){    
    return (num & ~( 1 << n));
}

int toggle_nth_bit(int num, int n){    
    return num ^ (1 << n);
}

int check_nth_bit(int num, int n){    
    return num & (1 << n);
}
4
chux - Reinstate Monica 2017-09-28 08:18.

Làm thế nào để bạn thiết lập, xóa và chuyển đổi một chút?

Để giải quyết một lỗi mã hóa phổ biến khi cố gắng tạo mặt nạ:
1không phải lúc nào cũng đủ rộng

Những vấn đề gì xảy ra khi numbermột loại rộng hơn 1?
xcó thể quá lớn đối với sự thay đổi 1 << xdẫn đến hành vi không xác định (UB). Ngay cả khi xkhông quá lớn, ~có thể không lật đủ các bit quan trọng nhất.

// assume 32 bit int/unsigned
unsigned long long number = foo();

unsigned x = 40; 
number |= (1 << x);  // UB
number ^= (1 << x);  // UB
number &= ~(1 << x); // UB

x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough

Để đảm bảo 1 đủ rộng:

Mã có thể sử dụng 1ullhoặc theo phương pháp (uintmax_t)1và để trình biên dịch tối ưu hóa.

number |= (1ull << x);
number |= ((uintmax_t)1 << x);

Hoặc truyền - điều này giải quyết các vấn đề về mã hóa / xem xét / bảo trì, giữ cho quá trình truyền chính xác và cập nhật.

number |= (type_of_number)1 << x;

Hoặc nhẹ nhàng quảng bá 1bằng cách buộc một phép toán có độ rộng ít nhất bằng loại number.

number |= (number*0 + 1) << x;

Như với hầu hết các thao tác bit, tốt nhất để làm việc với unsigned loại chứ không phải ký kết những

3
Joakim L. Christiansen 2018-02-11 10:07.

Một phiên bản được tạo mẫu (đặt trong tệp tiêu đề) với hỗ trợ thay đổi nhiều bit (hoạt động trên vi điều khiển AVR btw):

namespace bit {
  template <typename T1, typename T2>
  constexpr inline T1 bitmask(T2 bit) 
  {return (T1)1 << bit;}
  template <typename T1, typename T3, typename ...T2>
  constexpr inline T1 bitmask(T3 bit, T2 ...bits) 
  {return ((T1)1 << bit) | bitmask<T1>(bits...);}

  /** Set these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void set (T1 &variable, T2 ...bits) 
  {variable |= bitmask<T1>(bits...);}
  /** Set only these bits (others will be cleared) */
  template <typename T1, typename ...T2>
  constexpr inline void setOnly (T1 &variable, T2 ...bits) 
  {variable = bitmask<T1>(bits...);}
  /** Clear these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void clear (T1 &variable, T2 ...bits) 
  {variable &= ~bitmask<T1>(bits...);}
  /** Flip these bits (others retain their state) */
  template <typename T1, typename ...T2>
  constexpr inline void flip (T1 &variable, T2 ...bits) 
  {variable ^= bitmask<T1>(bits...);}
  /** Check if any of these bits are set */
  template <typename T1, typename ...T2>
  constexpr inline bool isAnySet(const T1 &variable, T2 ...bits) 
  {return variable & bitmask<T1>(bits...);}
  /** Check if all these bits are set */
  template <typename T1, typename ...T2>
  constexpr inline bool isSet (const T1 &variable, T2 ...bits) 
  {return ((variable & bitmask<T1>(bits...)) == bitmask<T1>(bits...));}
  /** Check if all these bits are not set */
  template <typename T1, typename ...T2>
  constexpr inline bool isNotSet (const T1 &variable, T2 ...bits) 
  {return ((variable & bitmask<T1>(bits...)) != bitmask<T1>(bits...));}
}

Ví dụ sử dụng:

#include <iostream>
#include <bitset> // for console output of binary values

// and include the code above of course

using namespace std;

int main() {
  uint8_t v = 0b1111'1100;
  bit::set(v, 0);
  cout << bitset<8>(v) << endl;

  bit::clear(v, 0,1);
  cout << bitset<8>(v) << endl;

  bit::flip(v, 0,1);
  cout << bitset<8>(v) << endl;

  bit::clear(v, 0,1,2,3,4,5,6,7);
  cout << bitset<8>(v) << endl;

  bit::flip(v, 0,7);
  cout << bitset<8>(v) << endl;
}

BTW: Hóa ra là constexpr và inline không được sử dụng nếu không gửi đối số của trình tối ưu hóa (ví dụ: -O3) tới trình biên dịch. Hãy thử mã tạihttps://godbolt.org/ và nhìn vào đầu ra ASM.

1
Balaji Boggaram Ramanarayan 2020-04-23 10:30.

Chương trình này dựa trên giải pháp trên của @ Jeremy. Nếu ai đó muốn nhanh chóng chơi xung quanh.

public class BitwiseOperations {

    public static void main(String args[]) {

        setABit(0, 4); // set the 4th bit, 0000 -> 1000 [8]
        clearABit(16, 5); // clear the 5th bit, 10000 -> 00000 [0]
        toggleABit(8, 4); // toggle the 4th bit, 1000 -> 0000 [0]
        checkABit(8,4); // check the 4th bit 1000 -> true 
    }

    public static void setABit(int input, int n) {
        input = input | ( 1 << n-1);
        System.out.println(input);
    }


    public static void clearABit(int input, int n) {
        input = input & ~(1 << n-1);
        System.out.println(input);
    }

    public static void toggleABit(int input, int n) {
        input = input ^ (1 << n-1);
        System.out.println(input);
    }

    public static void checkABit(int input, int n) {
        boolean isSet = ((input >> n-1) & 1) == 1; 
        System.out.println(isSet);
    }
}


Output :
8
0
0
true
1
aniketvaishnav 2020-09-10 14:33.

Trong Java, sử dụng lớp BitSet ( java.util.BitSet) có thể hữu ích. Nó cũng có các phương pháp cần thiết thường xuyên. Khi cần xử lý bit và không biết giới hạn trên, sử dụng BitSet có thể được chứng minh là một lựa chọn tốt.

Đối với số như một đối tượng của BitSet.
Bạn có thể,

Đặt một chút cụ thể

number.set(indexOfTargetedBit)

Xóa một chút cụ thể

number.clear(indexOfTargetedBit)

Chuyển đổi một chút cụ thể

number.flip(indexOfTargetedBit)

Bạn có thể biết thêm thông tin chi tiết về BitSet tại đây

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Tận dụng lợi thế của việc bán hàng nhân Ngày của Cha này

Tận dụng lợi thế của việc bán hàng nhân Ngày của Cha này

Màn hình Samsung Galaxy S9 Plus. Chủ nhật này là Ngày của Cha⁠ — trong trường hợp nó khiến bạn suy nghĩ — và thay vì mua cho anh ấy một chiếc cà vạt trong năm nay, có lẽ đã đến lúc bạn mua cho anh ấy thứ mà anh ấy sẽ thực sự sử dụng.

Assassin's Creed Snuck Into Monster Hunter: World Last Night

Assassin's Creed Snuck Into Monster Hunter: World Last Night

Monster Hunter: World yêu thích các sự kiện chéo. Dù có nghĩa là hóa trang thành Dante của Devil May Cry, giả dạng Horizon: Zero Dawn's Aloy, hay chiến đấu với quái vật Final Fantasy, các nhiệm vụ sự kiện khác nhau của Thế giới được nâng cấp tự do so với các trò chơi khác.

Ava DuVernay Có Quà Tặng Ngày Của Mẹ cho Tất Cả Chúng Ta: Nếp Nhăn Thời Gian Sẽ Được Viết Lại Vào Cuối Tuần Ngày Của Mẹ!

Ava DuVernay Có Quà Tặng Ngày Của Mẹ cho Tất Cả Chúng Ta: Nếp Nhăn Thời Gian Sẽ Được Viết Lại Vào Cuối Tuần Ngày Của Mẹ!

Storm Reid, Oprah Winfrey, Mindy Kaling, Reese Witherspoon và Ava DuVernay tại buổi chiếu đặc biệt của A Wrinkle in Time tại Nhà hát Walter Reade ở Thành phố New York vào ngày 7 tháng 3 năm 2018 “Ava rất mong được nói chuyện với bạn,” một trong những người của Array dư luận viên nói qua điện thoại. (Array là tập thể phân phối, nghệ thuật và vận động chính sách của Ava DuVernay tập trung vào các bộ phim của người da màu và phụ nữ.

Nhiệm vụ bất khả thi 5 sẽ khôi phục niềm tin của bạn trong phim hành động Tentpole

Nhiệm vụ bất khả thi 5 sẽ khôi phục niềm tin của bạn trong phim hành động Tentpole

Mission Impossible: Rogue Nation bắt đầu ở một cấp độ khác. Theo nghĩa đen.

Edwin McCain ra mắt Grand Ole Opry: Quay cảnh hậu trường với nhạc sĩ 'I'll Be'

Edwin McCain ra mắt Grand Ole Opry: Quay cảnh hậu trường với nhạc sĩ 'I'll Be'

McCain, người đang làm việc cho một album mới, lần đầu tiên bước vào vòng kết nối vào tối thứ Sáu ở Nashville

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Tôi viết như thế nào

Tôi viết như thế nào

Đối với tôi, mọi thứ là về dòng đầu tiên đó và nó sẽ đưa bạn đến đâu. Một số nhà văn bị điều khiển bởi cốt truyện, sự sắp xếp tinh tế của các quân cờ, trong khi những người khác bị lôi cuốn bởi một nhân vật và khả năng thực hiện một cuộc hành trình với một người bạn hư cấu mới.

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Language