비트를 어떻게 설정하고 지우고 토글합니까?
비트를 어떻게 설정하고 지우고 토글합니까?
답변:
비트 OR 연산자 ( |
)를 사용하여 비트 를 설정하십시오.
number |= 1UL << n;
의 n
비트 가 설정됩니다 number
. st 비트 n
를 설정하려면 1
up 을 0 n-1
으로 설정하고 n
th 비트 를 설정하려면
보다 넓은 1ULL
경우 사용 ; 의 너비 이상으로 이동하는 정의되지 않은 동작이 어디인지 평가 한 후에야 프로모션이 진행 됩니다. 나머지 모든 예제에도 동일하게 적용됩니다.number
unsigned long
1UL << n
1UL << n
long
비트 AND 연산자 ( &
)를 사용하여 비트 를 지 웁니다.
number &= ~(1UL << n);
그것의 n
th 비트를 취소합니다 number
. 비트 NOT 연산자 ( ~
)를 사용하여 비트 문자열을 반전 한 다음 AND해야합니다.
XOR 연산자 ( ^
)를 사용하여 비트를 토글 할 수 있습니다.
number ^= 1UL << n;
의 n
th 비트를 토글합니다 number
.
당신은 이것을 요구하지 않았지만 나는 그것을 추가 할 수도 있습니다.
비트를 확인하려면 숫자 n을 오른쪽으로 이동 한 다음 비트 AND로 이동하십시오.
bit = (number >> n) & 1U;
그것은 n
th 비트의 값을 number
변수 에 넣을 것입니다 bit
.
2의 보수 C ++ 구현에서 다음과 같이 n
th 비트를 설정 1
하거나 0
달성 할 수 있습니다.
number ^= (-x ^ number) & (1UL << n);
비트는 n
경우 설정 될 것 x
입니다 1
, 그리고 경우 삭제 x
입니다 0
. x
다른 가치가 있다면 쓰레기가 생깁니다. x = !!x
0 또는 1로 부울합니다.
이것을 2의 보수 부정 행위 ( -1
1의 보수 또는 부호 / 크기 C ++ 구현과는 달리 모든 비트가 설정되어 있음)와 독립적으로 만들려면 부호없는 부정을 사용하십시오.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
또는
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
휴대용 비트 조작에 부호없는 유형을 사용하는 것이 일반적으로 좋습니다.
또는
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
맑은 것 n
번째 비트를하고 (x << n)
설정된 것 n
에 번째 비트를 x
.
일반적으로 코드를 복사 / 붙여 넣기하지 않는 것이 좋으며, 많은 사람들이 프리 프로세서 매크로 ( 커뮤니티 Wiki의 답변 아래로 ) 또는 캡슐화를 사용합니다.
bit = (number >> x) & 1
1
int
서명 된 리터럴입니다. 따라서 여기의 모든 작업은 표준에 의해 잘 정의되지 않은 부호있는 숫자로 작동합니다. 표준은 2의 보수 또는 산술 시프트를 보장하지 않으므로 사용하는 것이 좋습니다 1U
.
number = number & ~(1 << n) | (x << n);
n 번째 비트를 x로 변경하는 것을 선호 합니다.
표준 C ++ 라이브러리 사용 : std::bitset<N>
.
또는 부스트 버전 : boost::dynamic_bitset
.
자신의 것을 굴릴 필요가 없습니다.
#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
Boost 버전은 표준 라이브러리 컴파일 타임 크기 비트 세트와 비교하여 런타임 크기 비트 세트를 허용합니다 .
다른 옵션은 비트 필드를 사용하는 것입니다.
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
3 비트 필드를 정의합니다 (실제로 3 비트의 1 비트 필드). 비트 작업이 이제 조금 더 간단 해졌습니다 (haha).
비트를 설정하거나 지우려면 :
mybits.b = 1;
mybits.c = 0;
비트를 토글하려면 :
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
조금 확인 :
if (mybits.c) //if mybits.c is non zero the next line below will execute
이것은 고정 크기 비트 필드에서만 작동합니다. 그렇지 않으면 이전 게시물에서 설명한 비트 트위들 링 기술에 의존해야합니다.
비트 파일을 처리하고 지우기 위해 헤더 파일에 정의 된 매크로를 사용합니다.
/* 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))
BITMASK_CHECK(x,y) ((x) & (y))
((x) & (y)) == (y)
그렇지 않으면 멀티 비트 마스크에서 잘못된 결과를 반환 해야합니다 (예 : 5
vs. 3
) / * Hello 모든 묘비에게 :) * /
1
(uintmax_t)1
누군가이 매크로를 long
더 큰 유형 에서 사용하려고 할 경우에 유사하거나 유사 해야합니다.
BITMASK_CHECK_ALL(x,y)
다음과 같이 구현 될 수 있음!~((~(y))|(x))
!(~(x) & (y))
때때로 비트 이름enum
을 지정 하기 위해를 사용하는 것이 좋습니다 :
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
그런 다음 나중에 이름을 사용하십시오 . 즉 쓰기
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
설정하고 지우고 테스트합니다. 이 방법으로 나머지 코드에서 마법의 숫자를 숨길 수 있습니다.
그 외에는 Jeremy의 솔루션을 보증합니다.
clearbits()
대신에 기능을 만들 수 &= ~
있습니다. 왜 이것을 위해 열거 형을 사용하고 있습니까? 나는 그것들이 숨겨진 임의의 값으로 고유 한 변수를 생성하기위한 것이라고 생각했지만 각각에 명확한 값을 할당하고 있습니다. 그렇다면 변수로 정의하는 것의 장점은 무엇입니까?
enum
관련된 상수 세트 에 s를 사용하면 c 프로그래밍에서 먼 길을 갔다. 현대 컴파일러의 유일한 장점 const short
은 명시 적으로 그룹화되어 있다는 것 이상의 이점 이 있다고 생각합니다. 그리고 비트 마스크 이외의 다른 것을 원할 때 자동 번호 매기기를 얻습니다. 물론 C ++에서는 고유 한 유형을 형성하여 정적 오류 검사를 약간 추가합니다.
enum ThingFlags
값은 무엇입니까 ThingError|ThingFlag1
?
int
. 암시 적 정수 승격 또는 부호있는 유형에 대한 비트 단위 연산으로 인해 모든 방식의 미묘한 버그가 발생할 수 있습니다. thingstate = ThingFlag1 >> 1
예를 들어 구현 정의 동작을 호출합니다. thingstate = (ThingFlag1 >> x) << y
정의되지 않은 동작을 호출 할 수 있습니다. 등등. 안전을 위해 항상 부호없는 유형으로 캐스트하십시오.
enum My16Bits: unsigned short { ... };
/*
** 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의 필드를 만듭니다. 까다로운 부분은 BitClr () 매크로에 있으며 1의 필드에 단일 0 비트를 설정해야합니다. 이는 물결표 (~) 연산자로 표시된 것과 동일한 식의 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 (분해)] -------------------------------------- ---------
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] ------------------------------------------- ----------------------
arg
입니다 long long
. 1L
가장 넓은 유형이어야합니다 (uintmax_t)1
. (당신은 도망 갈 수 있습니다 1ull
)
비트 연산자를 사용하십시오. &
|
마지막 비트를 설정하려면 000b
:
foo = foo | 001b
마지막 비트를 확인하려면 foo
:
if ( foo & 001b ) ....
마지막 비트를 지우려면 foo
:
foo = foo & 110b
나는 XXXb
명확성을 위해 사용 했다. 비트를 패킹하는 데이터 구조에 따라 HEX 표현으로 작업하고있을 것입니다.
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
초보자에게는 예를 들어 조금 더 설명하고 싶습니다.
예:
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, &)) ...
기타
BITOP(array, bit++, |=);
루프에서 사용 하면 발신자가 원하는 것을 수행하지 않을 가능성이 높습니다.
BITCELL(a,b) |= BITMASK(a,b);
(모두 테이크 a
인수로는 크기를 결정하지만, 후자는 평가하지 않을 것 a
때문에 sizeof
) 에만 나타납니다 .
(size_t)
캐스트가 될 일부 보장하는 것 부호 수학을 함께 %
. (unsigned)
거기 에요
(size_t)(b)/(8*sizeof *(a))
불필요하게는 축소 할 수 b
분할하기 전에. 매우 큰 비트 배열에만 문제가 있습니다. 여전히 흥미로운 매크로입니다.
"embedded"태그가 붙어 있으므로 마이크로 컨트롤러를 사용한다고 가정하겠습니다. 위의 모든 제안은 유효하며 작동합니다 (읽기-수정-쓰기, 공용체, 구조체 등).
그러나 오실로스코프 기반 디버깅이 진행되는 동안 이러한 방법이 마이크로의 PORTnSET / PORTnCLEAR 레지스터에 직접 값을 쓰는 것과 비교할 때 CPU 사이클에서 상당한 오버 헤드가 있다는 사실에 놀랐습니다. 주파수 ISR의 토글 핀.
익숙하지 않은 사람들을 위해 : 나의 예에서, 마이크로는 출력 핀을 반영하는 일반적인 핀 상태 레지스터 PORTn을 가지고 있으므로, PORTn | = BIT_TO_SET을 수행하면 해당 레지스터에 대한 읽기-수정-쓰기가 발생합니다. 그러나 PORTnSET / PORTnCLEAR 레지스터는 "이 비트를 1로 설정하십시오"(SET) 또는 "이 비트를 0으로 설정하십시오"(CLEAR)를 의미하고 "0"은 "핀을 그대로 두십시오"를 의미하는 '1'을 사용합니다. 따라서 비트를 설정 또는 해제하는지 (항상 편리하지는 않지만) 훨씬 빠른 반응 및 작은 조립 코드에 따라 두 개의 포트 주소가 생깁니다 .
volatile
되므로 컴파일러는 해당 레지스터와 관련된 코드에서 최적화를 수행 할 수 없습니다. 따라서 이러한 코드를 분해하고 어셈블러 수준에서 어떻게 작동하는지 확인하는 것이 좋습니다.
비트 필드 방식은 임베디드 분야에서 다른 이점을 제공합니다. 특정 하드웨어 레지스터의 비트에 직접 매핑되는 구조체를 정의 할 수 있습니다.
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라고 생각하지만 구현에 따라 다를 수 있습니다. 또한 컴파일러가 바이트 경계를 넘는 필드를 처리하는 방법을 확인하십시오.
그런 다음 이전과 같이 개별 값을 읽고 쓰고 테스트 할 수 있습니다.
#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을 사용하여 테스트했습니다. 비트를 설정하고 지우는 비슷한 매크로를 만들 수 있습니다. 이 솔루션과 다른 많은 솔루션의 주요 차이점은 거의 모든 유형의 변수에서 모든 위치에서 작동한다는 것입니다.
임의 크기의 비트 맵의 경우 더 일반적입니다.
#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)))
CHAR_BIT
에 의해 이미 정의되었으므로 limits.h
직접 입력 할 필요는 없습니다 BITS
(실제로 코드를 더 나쁘게 만들 수도 있습니다)
이 프로그램은 데이터 비트를 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);
}
}
}
많은 비트를 돌리고 있다면 마스크를 사용하여 모든 것을 빠르게 할 수 있습니다. 다음 함수는 매우 빠르고 유연합니다 (모든 크기의 비트 맵에서 비트 트위들 링 허용).
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;
}
16 비트 정수로 비트 'n'을 설정하려면 다음을 수행하십시오.
TSetBit( n, &my_int);
비트 번호가 전달한 비트 맵 범위 내에 있는지 확인하는 것은 사용자의 책임입니다. 바이트, 단어, dwords, qwords 등이 리틀 엔디안 프로세서의 경우 메모리에서 서로 올바르게 매핑됩니다 (작은 엔디안 프로세서가 빅 엔디안 프로세서보다 '더 나은'것입니다) 의 위에...).
이것을 사용하십시오 :
int ToggleNthBit ( unsigned char n, int num )
{
if(num & (1 << n))
num &= ~(1 << n);
else
num |= (1 << n);
return num;
}
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;
}
Linux 커널 에서 C 프로그래밍 으로이 모든 작업을 수행하려면 Linux 커널의 표준 API를 사용하는 것이 좋습니다.
참조 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
참고 : 여기서 전체 작업은 단일 단계로 수행됩니다. 따라서 이러한 모든 기능은 SMP 컴퓨터에서도 원 자성 이 보장 되며 프로세서간에 일관성을 유지하는 데 유용합니다.
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
설정 및 지우기 부울을 쉽게하십시오.
인쇄 할 수없는 문자를 찾으려면
// 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 개의 값과 2 개의 값만 보유 할 수있는 1 비트 정수
한 번은이 접근 방식을 사용하여 6 자리 대출 번호를 비트 배열의 인덱스로 사용하여 loan_number가 ISAM 키인 중복 대출 레코드를 찾았습니다. 엄청나게 빠르며 8 개월 후 데이터를 수집 한 메인 프레임 시스템이 실제로 오작동하고 있음을 증명했습니다. 비트 배열의 단순성으로 인해 검색 접근 방식과 비교하여 정확성이 매우 높습니다.
bool
. int
구현 하는 데 사용 되는 C89 설정의 경우 4 바이트 일 수도 있습니다.bool
내가 사용하는 매크로는 다음과 같습니다.
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)
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);
}
check_nth_bit
될 수 있습니다 bool
.
num = 55
Integer에서 비트 단위 연산 (설정, 가져 오기, 지우기, 토글)을 수행하기 위해 가장 먼저 몇 가지를 가정 해 봅시다 .
n = 4
비트 단위 연산을 수행하는 0 기반 비트 위치.
nth
숫자 오른쪽 시프트 num
, 비트 를 얻으려면 n
. 그런 다음 &
1로 비트 AND 를 수행하십시오 .bit = (num >> n) & 1;
어떻게 작동합니까?
0011 0111 (55 in decimal)
>> 4 (right shift 4 times)
-----------------
0000 0011
& 0000 0001 (1 in decimal)
-----------------
=> 0000 0001 (final result)
n
번 교대 . 그런 다음로 비트 OR |
연산을 수행하십시오 num
.num |= (1 << n); // Equivalent to; num = (1 << n) | num;
어떻게 작동합니까?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
| 0011 0111 (55 in decimal)
-----------------
=> 0001 0000 (final result)
n
시간 1 << n
.~ (1 << n)
됩니다.&
위의 결과와로 비트 AND 연산을 수행 하십시오 num
. 위의 세 단계는 다음과 같이 작성할 수 있습니다 num & (~ (1 << n))
.num &= (~(1 << n)); // Equivalent to; num = num & (~(1 << n));
어떻게 작동합니까?
0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
~ 0001 0000
-----------------
1110 1111
& 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
비트를 토글하기 위해 비트 XOR ^
연산자를 사용합니다. 비트 XOR 연산자는 두 피연산자의 해당 비트가 다른 경우 1로 평가되고, 그렇지 않으면 0으로 평가됩니다.
즉, 비트를 토글하려면 토글하려는 비트와 1로 XOR 연산을 수행해야합니다.
num ^= (1 << n); // Equivalent to; num = num ^ (1 << n);
어떻게 작동합니까?
0 ^ 1 => 1
. 1 ^ 1 => 0
. 0000 0001 (1 in decimal)
<< 4 (left shift 4 times)
-----------------
0001 0000
^ 0011 0111 (55 in decimal)
-----------------
=> 0010 0111 (final result)
권장 자료- 비트 단위 연산자 연습
단일 비트를 어떻게 설정하고 지우고 토글합니까?
마스크를 형성하려고 할 때 일반적인 코딩 함정을 해결하려면
1
항상 충분히 넓지는 않습니다.
number
보다 넓은 유형의 경우 어떤 문제가 발생 1
합니까? 정의되지 않은 동작 (UB)으로 이어지는
x
변화에 비해 너무 클 수 있습니다 . 너무 크지 않더라도 가장 중요한 비트를 충분히 뒤집지 않을 수 있습니다.1 << x
x
~
// 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;
와 작업에 대부분의 비트 조작, 최고의와 마찬가지로 서명되지 않은 유형이 아닌 서명 것들
number |= (type_of_number)1 << x;
것도 number |= (number*0 + 1) << x;
적절 하지도 않습니다 ... 사실, 어느 것도 아닙니다 number |= (1ull << x);
. 위치별로 휴대 할 수있는 방법이 있습니까?
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;}
}
;
함수 정의 후에 왜
(variable & bits == bits)
?
((variable & bits) == bits)
std::bitset
c ++ 11에서 사용
이 프로그램은 @Jeremy의 위 솔루션을 기반으로합니다. 누군가가 빨리 놀기를 원한다면.
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
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;
}
value << n
정의되지 않은 동작이 발생할 수 있습니다