c++ operator 단일 비트를 설정, 지우기 및 전환하려면 어떻게 해야 합니까?




c++ bitwise operator example (21)

사용 된 변수

int value, pos;

값 - 데이터
POS - 우리가 설정 한 관심이 명확 중이거나 토글 비트의 위치에
약간의 설정

value = value | 1 << pos;

조금 지우기

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

조금 토글하다.

value = value ^ 1 << pos;

C / C ++에서 어떻게 비트를 설정, 해제 및 토글합니까?


bitset 응답 확대 :

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

이 프로그램은 모든 데이터 비트를 0에서 1 또는 1에서 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);
        }
    }
}

단일 비트를 어떻게 설정, 해제 및 토글합니까?

마스크를 만들 때 일반적인 코딩 함정을 해결하려면
1항상 충분히 넓지는 않습니다.

number보다 큰 유형 이있을 때 어떤 문제가 발생 1합니까? 정의되지 않은 동작 (UB)으로 이어지는
x변화가 너무 클 수 있습니다 . 너무 크지 않더라도 , 최상위 비트를 충분히 뒤집을 수는 없습니다.1 << xx~

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

1이 충분히 넓은 지 확인하려면 다음을 수행하십시오.

코드 는 컴파일러를 최적화 1ull하거나 사용할 수 있습니다 (uintmax_t)1.

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

또는 캐스트 - 코딩 / 검토 / 유지 보수 문제로 캐스트가 정확하고 최신 상태로 유지됩니다.

number |= (type_of_number)1 << x;

또는 부드럽게 1유형을 최대한 넓히는 수학 연산을 강제로 수행하십시오 number.

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

대부분의 비트 조작과 마찬가지로, 최고와 함께 작동하는 부호없는 타입이 아닌 서명 것들


비트 필드 방식은 임베디드 분야에서 다른 장점을 가지고 있습니다. 특정 하드웨어 레지스터의 비트에 직접 매핑되는 구조체를 정의 할 수 있습니다.

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;

비트 포장 순서를 알고 있어야합니다. MSB가 먼저 나온 것 같지만 구현에 따라 다를 수 있습니다. 또한 컴파일러가 바이트 경계를 넘는 필드를 처리하는 방법을 확인하십시오.

이전과 마찬가지로 개별 값을 읽고 쓰고 테스트 할 수 있습니다.


헤더 파일에 정의 된 매크로를 사용하여 비트 세트를 처리하고 지 웁니다.

/* 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)) == (y))   // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (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)))

만약 당신이 많은 걸음을 터벅 터벅 걷고 있다면, 모든 것을 더 빠르게 할 마스크를 사용하고 싶어 할 것입니다. 다음 함수는 매우 빠르며 여전히 유연합니다 (모든 크기의 비트 맵에서 비트가 꼬이는 것을 허용합니다).

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

비트 'n'을 16 비트 정수로 설정하려면 다음을 수행하십시오.

TSetBit( n, &my_int);

비트 번호가 전달하는 비트 맵의 ​​범위 내에 있는지 확인하는 것은 사용자의 몫입니다. 작은 엔디안 프로세서의 경우 바이트, 단어, dwords, qwords 등이 메모리에서 서로 정확하게 매핑된다는 점에 유의하십시오 (리틀 엔디안 프로세서가 빅 엔디안 프로세서보다 '더 나은'주된 이유는 아), 나는 불꽃 전쟁이 올 것이라고 느낍니다. 에...).


임의의 유형의 변수에서 임의의 위치에있는 비트를 확인하십시오.

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

샘플 사용법 :

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

참고 사항 : 이 기능은 빠른 속도 (유연성 있음)와 비 분기 방식으로 설계되었습니다. Sun Studio 8을 컴파일하면 효율적인 SPARC 시스템 코드가 생성됩니다. 또한 amd64에서 MSVC ++ 2008을 사용하여 테스트했습니다. 비트를 설정하고 지우는 비슷한 매크로를 만들 수 있습니다. 이 솔루션의 주요 차이점은 많은 다른 유형과 비교하면 거의 모든 변수 유형의 모든 위치에서 작동한다는 것입니다.


이것을 사용하십시오 :

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

    return num;
}

C ++ 11 템플릿 버전 (헤더에 넣음) :

namespace bit {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bit) {variable |=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bit) {variable ^=  ((T1)1 << bit);}
    template <typename T1, typename T2> inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);}
}

namespace bitmask {
    template <typename T1, typename T2> inline void set  (T1 &variable, T2 bits) {variable |= bits;}
    template <typename T1, typename T2> inline void clear(T1 &variable, T2 bits) {variable &= ~bits;}
    template <typename T1, typename T2> inline void flip (T1 &variable, T2 bits) {variable ^= bits;}
    template <typename T1, typename T2> inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);}
    template <typename T1, typename T2> inline bool test_any(T1 &variable, T2 bits) {return variable & bits;}
}

초보자를 위해 예제를 통해 좀 더 설명하고 싶습니다.

예:

value is 0x55;
bitnum : 3rd.

& 연산자가 비트를 검사하는 데 사용됩니다.

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)

토글 또는 뒤집기 :

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

| 연산자 : 비트 설정

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)

다음은 unsigned char 에서부터 size_t (작업 할 수있는 가장 큰 유형)까지의 모든 유형의 부호없는 정수 배열에서 작동하는 가장 좋아하는 비트 산술 매크로입니다.

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

비트를 설정하려면,

BITOP(array, bit, |=);

비트를 지우려면 :

BITOP(array, bit, &=~);

비트를 토글하려면 :

BITOP(array, bit, ^=);

비트를 테스트하려면 다음을 수행하십시오.

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

기타


이것은 "임베디드"라는 태그가 붙어 있으므로 마이크로 컨트롤러를 사용하고 있다고 가정합니다. 위의 제안은 모두 유효하며 작동합니다 (읽기 - 수정 - 쓰기, 공용체, 구조체 등).

그러나 오실로스코프 기반 디버깅 중에는 마이크로의 PORTnSET / PORTnCLEAR 레지스터에 값을 직접 쓰는 것과 비교하여 CPU 사이클에 상당한 오버 헤드가있는 것을 발견하게되어 놀라웠습니다. ISR의 토글 핀.

익숙하지 않은 분들을 위해 : 필자의 예에서는 마이크로가 출력 핀을 반영하는 일반적인 핀 상태 레지스터 PORTn을 가지고 있으므로 PORTn | = BIT_TO_SET을하면 해당 레지스터에 대한 읽기 - 수정 - 쓰기 결과가 발생합니다. 그러나 PORTnSET / PORTnCLEAR 레지스터는 "이 비트 1을 만드십시오"(SET) 또는 "이 비트를 0으로 만드십시오"(CLEAR)를 의미하는 "1"을 취하고 "핀을 홀로 두십시오"를 의미하는 '0'을가집니다. 따라서 비트 설정 또는 비우기 (항상 편리한 것은 아님)에 따라 두 포트 주소가 필요하지만 훨씬 더 빠른 반응과 더 작은 어셈블 된 코드가 필요합니다.


here 정의 된 연산자 중 하나를 사용 here .

비트를 설정하려면 , 비트 위치가 int x = x | 0x?;어디에 ?바이너리 형태로 사용 되는지 .


Visual C 2010과 다른 많은 컴파일러는 비트 연산을 직접 지원합니다. 놀랍게도 sizeof () 연산자조차 제대로 작동합니다.

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

그래서 질문에 IsGph [i] = 1 또는 IsGph [i] = 0은 bool을 쉽게 설정하고 지울 수있게 해줍니다.

인쇄 할 수없는 문자를 찾으려면 ...

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

이 코드에는 "특별한"것이 없습니다. 그것은 마치 정수처럼 취급합니다 - 기술적으로는 그렇습니다. 2 개의 값을 가질 수있는 1 비트 정수와 2 개의 값만.

한 번이 방법을 사용하여 loan_number가 ISAM 키인 중복 대출 레코드를 찾고 6 자리 대출 번호를 비트 배열의 인덱스로 사용했습니다. Savagely fast, 그리고 8 개월 후, 우리가 데이터를 얻는 메인 프레임 시스템이 실제로 오작동하고 있음을 증명했습니다. 비트 어레이의 단순성은 정확성에 대한 신뢰를 매우 높게합니다.


내가 사용하는 매크로는 다음과 같습니다.

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)

조금 설정하기

비트 OR 연산자 ( | )를 사용하여 비트를 설정하십시오.

number |= 1UL << n;

그러면 numbern 번째 비트가 설정됩니다. n 번째 비트를 설정하려면 1 번째 비트를 설정하고 n-1 개까지 설정하려면 n 이 0이어야합니다.

numberunsigned long 보다 더 넓은 경우 1ULL 사용하십시오. 1UL << n1UL << n 을 평가 한 1UL << n 정의 된 행동이 long 의 너비 이상으로 1UL << n 때까지 발생하지 않습니다. 나머지 예제들도 마찬가지입니다.

조금 치우다.

비트 AND 연산자 ( & )를 사용하여 비트를 지 웁니다.

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

그러면 numbern 번째 비트가 number 집니다. 비트 NOT 연산자 ( ~ )로 비트 문자열을 반전 한 다음 AND로 반올림해야합니다.

조금 토글

XOR 연산자 ( ^ )를 사용하여 비트를 토글 할 수 있습니다.

number ^= 1UL << n;

그러면 numbern 번째 비트가 토글됩니다.

조금 확인하기

너는 이것을 요구하지 않았지만 나는 그것을 덧붙일지도 모른다.

비트를 확인하려면 숫자 n을 오른쪽으로 이동 한 다음 비트 단위로 AND를합니다.

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

그러면 numbern 번째 비트 값이 변수 bit 됩니다.

n 번째 비트를 x로 변경

n 번째 비트를 1 또는 0 설정하는 것은 2의 보수 C ++ 구현에서 다음을 수행하여 수행 할 수 있습니다.

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

비트 nx1 이면 설정되고 x0 지워집니다. x 가 다른 값을 가지면 쓰레기가 생깁니다. x = !!x 는 0 또는 1로 부울 화합니다.

이것을 2의 보수 네거티브 동작 ( -1 은 1의 보수 또는 부호 / 크기 C ++ 구현과 달리 -1 을 제외한 모든 비트를 설정 함)과 독립적으로 만들려면 부호없는 부정을 사용하십시오.

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

또는

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

일반적으로 휴대용 비트 조작에 부호없는 유형을 사용하는 것이 좋습니다.

또한 일반적으로 코드를 복사 / 붙여 넣지 않는 것이 좋습니다. 많은 사람들이 전처리 매크로 (예 : 커뮤니티 위키 답변 과 같은) 또는 일종의 캡슐화를 사용합니다.


snip-c.zip 의 bitops.h에서 :

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

좋아, 분석 해보자 ...

당신이 이것들에 문제가있는 것 같은 공통 표현은 "(1L << (posn))"입니다. 이 모든 작업은 단일 비트가있는 마스크를 만들고 모든 정수 유형에서 작동합니다. "posn"인수는 원하는 비트 위치를 지정합니다. posn == 0이면이 표현식은 다음과 같이 평가됩니다.

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

만약 posn == 8이라면,

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

즉, 지정된 위치에 1이있는 0의 필드를 만듭니다. 유일한 까다로운 부분은 1의 필드에 단일 0 비트를 설정해야하는 BitClr () 매크로입니다. 이것은 물결표 (~) 연산자로 표시된 것과 같은 표현식의 1의 보수를 사용하여 수행됩니다.

마스크가 만들어지면 비트와 (&), 또는 (|) 및 xor (^) 연산자를 사용하여 제안한 것과 마찬가지로 인수에 적용됩니다. 마스크는 long 타입이기 때문에 매크로는 char, short, int 또는 long에서 잘 작동합니다.

결론은 이것이 전체 종류의 문제에 대한 일반적인 해결책이라는 것입니다. 물론 필요할 때마다 이러한 매크로 중 하나와 동일한 매크로를 명시 적 마스크 값으로 다시 작성하는 것이 가능하고 적절한 방법 일 수도 있습니다. 매크로 치환은 전처리 기에서 발생하므로 생성 된 코드는 컴파일러에서 값이 상수로 간주된다는 사실을 반영합니다. 즉, 필요할 때마다 "바퀴 다시 만들기"와 같은 일반화 된 매크로를 사용하는 것이 효율적입니다. 비트 조작.

확신하지 못했습니까? 여기에 몇 가지 테스트 코드가 있습니다 - Watcom C를 전체 최적화와 _cdecl을 사용하지 않고 사용했기 때문에 결과물을 가능한 한 깨끗하게 정리할 수있었습니다 :

---- [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 (disassembled)] -------------------------------------- ---------

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

---- [finis] ------------------------------------------- ----------------------


enum사용 하여 비트를 명명 하는 것이 때때로 enum 할 수 있습니다.

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

그런 다음 나중에 이름을 사용하십시오. 즉

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

설정하고, 치우고, 테스트합니다. 이렇게하면 나머지 코드에서 매직 넘버를 숨길 수 있습니다.

그 외에는 Jeremy의 솔루션을지지합니다.


C 언어에서 다음 함수 중 하나를 사용하여 n 비트를 변경하십시오.

char bitfield;

// Start at 0th position

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) ));
}

또는

void chang_n_bit(int n, int value)
{
    bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n)));
}

또는

void chang_n_bit(int n, int value)
{
    if(value)
        bitfield |= 1 << n;
    else
        bitfield &= ~0 ^ (1 << n);
}

char get_n_bit(int n)
{
    return (bitfield & (1 << n)) ? 1 : 0;
}






bitwise-operators