다음 비트 연산자의 실제 사용 사례는 무엇입니까?
- 과
- XOR
- 아니
- 또는
- 왼쪽 / 오른쪽 이동
다음 비트 연산자의 실제 사용 사례는 무엇입니까?
답변:
비트 필드 (플래그)
여러 "예 또는 아니오"속성으로 상태가 정의 된 것을 나타내는 가장 효율적인 방법입니다. ACL이 좋은 예입니다. 4 개의 개별 권한 (읽기, 쓰기, 실행, 정책 변경)을 말한 경우이를 낭비보다 1 바이트로 저장하는 것이 좋습니다. 추가 편의를 위해 여러 언어로 열거 유형에 맵핑 할 수 있습니다.
포트 / 소켓을 통한 통신
은 항상 체크섬, 패리티, 정지 비트, 흐름 제어 알고리즘 등을 포함합니다. 매체는 1 비트 만 전송할 수 있기 때문에 일반적으로 숫자 값이 아닌 개별 바이트의 논리 값에 의존합니다. 시간.
압축, 암호화이
두 가지 모두 비트 알고리즘에 크게 의존합니다. 예제 는 deflate 알고리즘을 살펴보십시오. 모든 것이 바이트가 아니라 비트 단위입니다.
유한 상태 머신
소프트웨어에서도 찾을 수 있지만 주로 하드웨어에 내장 된 종류를 말합니다. 이들은 자연에서 조합 - 그들은 말 그대로 논리 게이트의 무리에 아래로 "컴파일"점점 될 수있다, 그들은 다음과 같이 표현 될 필요가 있으므로 AND
, OR
, NOT
, 등
그래픽
이 연산자가 그래픽 프로그래밍에 사용되는 모든 영역에 들어갈 공간이 충분하지 않습니다. XOR
(또는 ^
)는 동일한 입력을 두 번 적용하면 첫 번째가 실행 취소되므로 여기에서 특히 흥미 롭습니다. 이전 GUI는 값 비싼 다시 그리기의 필요성을 제거하기 위해 선택 강조 표시 및 기타 오버레이에이 방법을 사용했습니다. 느린 그래픽 프로토콜 (예 : 원격 데스크톱)에 여전히 유용합니다.
그것들은 내가 생각해 낸 처음 몇 가지 예일뿐입니다.
다음은 개별 비트로 저장된 플래그를 다루는 일반적인 관용구입니다.
enum CDRIndicators {
Local = 1 << 0,
External = 1 << 1,
CallerIDMissing = 1 << 2,
Chargeable = 1 << 3
};
unsigned int flags = 0;
청구 가능 플래그를 설정하십시오.
flags |= Chargeable;
CallerIDMissing 플래그 지우기 :
flags &= ~CallerIDMissing;
CallerIDMissing 및 Chargeable이 설정되어 있는지 테스트하십시오.
if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {
}
CMS의 보안 모델을 구현할 때 비트 단위 연산을 사용했습니다. 적절한 그룹에 있으면 사용자가 액세스 할 수있는 페이지가 있습니다. 사용자는 여러 그룹에 속할 수 있으므로 사용자 그룹과 페이지 그룹간에 교차가 있는지 확인해야했습니다. 따라서 각 그룹에 고유 한 2의 거듭 제곱 식별자를 할당했습니다. 예 :
Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100
이 값들을 함께 OR하고 값을 페이지와 함께 단일 int로 저장합니다. 예를 들어 그룹 A & B가 페이지에 액세스 할 수있는 경우 페이지 액세스 제어로 값 3 (2 진은 00000011)을 저장합니다. 거의 같은 방식으로 ORed 그룹 식별자 값을 사용자와 함께 저장하여 그룹을 나타냅니다.
따라서 지정된 사용자가 주어진 페이지에 액세스 할 수 있는지 확인하려면 값을 함께 AND하고 값이 0이 아닌지 확인하면됩니다. 이 검사는 단일 명령, 루핑, 데이터베이스 왕복없이 구현되므로 매우 빠릅니다.
저수준 프로그래밍이 좋은 예입니다. 예를 들어, 일부 하드웨어가 원하는 작업을 수행하도록 메모리 매핑 된 레지스터에 특정 비트를 작성해야 할 수 있습니다.
volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t value;
uint32_t set_bit = 0x00010000;
uint32_t clear_bit = 0x00001000;
value = *register; // get current value from the register
value = value & ~clear_bit; // clear a bit
value = value | set_bit; // set a bit
*register = value; // write it back to the register
또한, htonl()
및 htons()
사용하여 구현 &
하고 |
(그 시스템에 연산자를 엔디안 (바이트 순서) 네트워크 순서와 일치하지 않습니다)
#define htons(a) ((((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8))
#define htonl(a) ((((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24))
htons()
및 htonl()
스왑하기 POSIX 함수이다 short
또는이 long
호스트 (로부터 h
네트워크 (행) 엔디안 n
) 바이트 순서.
htonl()
32 비트에 대한 int
가치인가? long
많은 언어에서 64 비트를 의미합니다.
예를 들어 팩 색상 값에서 RGB (A) 값을 가져 오는 데 사용합니다.
(a & b) >> c
보다 a % d / e
(ARGB를 나타내는 int에서 단일 색상 값을 추출하는 두 가지 방법) 보다 5 배 이상 빠릅니다 . 각각 10 억 반복에 대해 6.7 및 35.2입니다.
%
에서 모듈러스 연산자가 아니라 나머지 연산자이기 때문입니다. 양수 값과 동일하지만 음수 값과 다릅니다. 적절한 제한을 제공하는 경우 ( 예 : uint
대신에 전달 int
) 두 예제의 속도는 동일해야합니다.
부울 플래그가 많으면 모두 int에 저장하는 것을 좋아합니다.
비트 단위 AND를 사용하여 가져옵니다. 예를 들면 다음과 같습니다.
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
기타
if (flags.feature_one_is_one) { // turn on feature }
. ANSI C 표준에 있으므로 이식성이 문제가되지 않습니다.
& = AND :
특정 비트를 마스크 처리합니다.
표시되거나 표시되지 않아야하는 특정 비트를 정의하고 있습니다. 0x0 & x는 바이트의 모든 비트를 지우고 0xFF는 x를 변경하지 않습니다. 0x0F는 하위 니블의 비트를 표시합니다.
변환 :
비트 ID를 사용하여 더 짧은 변수를 더 긴 변수로 캐스트하려면 int의 -1은 0xFFFFFFFF이고 긴 -1은 0xFFFFFFFFFFFFFFFFFF이므로 비트를 조정해야합니다. 동일성을 유지하기 위해 변환 후 마스크를 적용합니다.
| = OR
비트를 설정하십시오. 비트가 이미 설정되어 있으면 비트가 독립적으로 설정됩니다. 많은 데이터 구조 (비트 필드)에는 IS_HSET = 0, IS_VSET = 1과 같은 플래그가 있으며이 플래그는 독립적으로 설정할 수 있습니다. 플래그를 설정하려면 IS_HSET | IS_VSET (C와 어셈블리에서는 읽기가 매우 편리합니다)
^ = XOR
동일하거나 다른 비트를 찾습니다.
~ = NOT
플립 비트.
이는 것을 표시 할 수있는 모든 가능한 로컬 비트 동작이 이러한 동작에 의해 구현 될 수있다. 따라서 원하는 경우 비트 연산만으로 ADD 명령어를 구현할 수 있습니다.
멋진 해킹 :
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
= ~
아니 어야한다고 생각합니다 |=
.
& = AND
왜 모든 비트를 지우고 싶습니까? 왜 수정되지 않은 바이트 버전을 얻고 싶습니까? 그리고 더 낮은 니블과 어떻게해야합니까?
xor
그 자체입니다. 낮은 니블을 추출해야 할 몇 가지 이유를 생각할 수 있습니다. 특히 그 낮은 니블이 데이터 구조의 일부이고 마스크 또는 OR
다른 구조체와 함께 사용하려는 경우 .
암호화는 모두 비트 단위 작업입니다.
이것은 비트 맵 이미지에서 바이트 형식으로 색상을 읽는 예입니다.
byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */
//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */
//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF; /* This now returns a red colour between 0x00 and 0xFF.
이 작은 예제가 도움이 되길 바랍니다 ....
오늘날 현대 언어의 추상적 세계에서 그리 많지는 않습니다. File IO는 이미 염두에 두는 쉬운 방법이지만 이미 구현 된 작업에 대해서는 비트 단위 작업을 수행하고 비트 작업을 사용하는 작업은 구현하지 않습니다. 여전히 쉬운 예제로,이 코드는 파일에서 읽기 전용 속성을 제거하여 c #에서 FileMode.Create를 지정하는 새 FileStream과 함께 사용할 수 있도록합니다.
//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
FileAttributes attributes = File.GetAttributes(targetName);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));
File.Delete(targetName);
}
사용자 지정 구현에 관한 한 최근의 예가 있습니다. 분산 응용 프로그램의 한 설치에서 다른 설치로 보안 메시지를 보내기위한 "메시지 센터"를 만들었습니다. 기본적으로 전자 메일과 유사하며받은 편지함, 보낼 편지함, 보낸 편지함 등이 포함되어 있지만 읽음 확인으로 배달이 보장되므로 "받은 편지함"및 "보낸 편지함"외에 추가 하위 폴더가 있습니다. 이것이받은 내용은 "받은 편지함"또는 "보낸 폴더"를 일반적으로 정의하기위한 요구 사항이었습니다. 보낸 폴더 중에서 읽은 것과 읽지 않은 것을 알아야합니다. 읽지 않은 것 중에서, 나는 무엇을 받았는지,받지 않은 것을 알아야합니다. 이 정보를 사용하여 로컬 데이터 소스를 필터링하고 적절한 정보를 표시하는 동적 where 절을 작성합니다.
열거 형을 구성하는 방법은 다음과 같습니다.
public enum MemoView :int
{
InboundMemos = 1, // 0000 0001
InboundMemosForMyOrders = 3, // 0000 0011
SentMemosAll = 16, // 0001 0000
SentMemosNotReceived = 48, // 0011
SentMemosReceivedNotRead = 80, // 0101
SentMemosRead = 144, // 1001
Outbox = 272, //0001 0001 0000
OutBoxErrors = 784 //0011 0001 0000
}
이것이 무엇을하는지 아십니까? "Inbox"열거 형 값 InboundMemos와 함께 (&)를 사용하여 InboundMemosForMyOrders가받은 편지함에 있음을 알고 있습니다.
다음은 현재 선택된 폴더에 대한보기를 정의하는 필터를 빌드하고 반환하는 메소드 버전입니다.
private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
{
string filter = string.Empty;
if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
{
filter = "<inbox filter conditions>";
if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
{
filter += "<my memo filter conditions>";
}
}
else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
{
//all sent items have originating system = to local
filter = "<memos leaving current system>";
if((view & MemoView.Outbox) == MemoView.Outbox)
{
...
}
else
{
//sent sub folders
filter += "<all sent items>";
if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
{
if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
{
filter += "<not received and not read conditions>";
}
else
filter += "<received and not read conditions>";
}
}
}
return filter;
}
매우 단순하지만 일반적으로 비트 단위 연산이 필요하지 않은 추상화 수준의 깔끔한 구현입니다.
나는 아무도 인터넷 시대에 대한 명백한 답변을 선택하지 않았다는 사실에 놀랐습니다. 서브넷에 유효한 네트워크 주소를 계산합니다.
일반적으로 비트 연산은 곱하기 / 나누기보다 빠릅니다. 따라서 변수 x에 9를 곱 해야하는 경우 x<<3 + x
보다 몇 사이클 더 빠릅니다 x*9
. 이 코드가 ISR 내에 있으면 응답 시간이 절약됩니다.
마찬가지로 배열을 순환 대기열로 사용하려면 비트 단위 작업으로 검사를 감싸는 것이 더 빠르고 우아합니다. (배열 크기는 2의 거듭 제곱이어야합니다). 예 : 삽입 / 삭제하려는 경우 tail = ((tail & MASK) + 1)
대신 대신 사용할 수 있습니다 tail = ((tail +1) < size) ? tail+1 : 0
.
또한 오류 플래그가 여러 오류 코드를 함께 보유하려는 경우 각 비트는 별도의 값을 보유 할 수 있습니다. 각 개별 오류 코드와 함께 검사 할 수 있습니다. 이것은 유닉스 오류 코드에서 사용됩니다.
또한 n 비트 비트 맵은 정말 시원하고 컴팩트 한 데이터 구조 일 수 있습니다. 크기가 n 인 리소스 풀을 할당하려는 경우 n 비트를 사용하여 현재 상태를 나타낼 수 있습니다.
숫자 x
는 2의 거듭 제곱입니까? (예를 들어 카운터가 증가하고 로그 횟수 만 수행되는 알고리즘에서 유용합니다.)
(x & (x - 1)) == 0
정수의 가장 높은 비트는 어느 것 x
입니까? (예를 들어,이 값보다 큰 최소 전력 2를 찾는 데 사용할 수 있습니다 x
)
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift
1
정수 의 가장 낮은 비트는 어느 것 x
입니까? (2로 나눌 수있는 횟수를 찾는 데 도움이됩니다.)
x & -x
x & -x
.
비트 연산자는 길이가 2의 제곱 인 배열을 반복하는 데 유용합니다. 많은 사람들이 언급했듯이 비트 연산자는 매우 유용하며 플래그 , 그래픽 , 네트워킹 , 암호화에 사용 됩니다. 뿐만 아니라 매우 빠릅니다. 개인적으로 가장 좋아하는 것은 조건 없이 배열 을 반복 하는 것 입니다. 당신이 있다고 가정 제로 인덱스 기반의 배열을 (예를 들어 첫 번째 요소의 인덱스 0) 당신은 그것을 무한 루프가 필요합니다. 무기한으로 나는 첫 번째 요소에서 마지막으로 가고 처음으로 돌아 오는 것을 의미합니다. 이를 구현하는 한 가지 방법은 다음과 같습니다.
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
if (i >= arr.length)
i = 0;
}
if 문 을 사용하지 않으려면 가장 간단한 방법입니다. 모듈러스 방법을 다음과 같이 사용할 수 있습니다 .
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
i = i % arr.length;
}
이 두 가지 방법의 단점은 정수 나누기 후에 나머지를 찾기 때문에 계수 연산자가 비싸다는 것입니다. 그리고 첫 번째 방법은 각 반복마다 if 문을 실행합니다 . 그러나 비트 연산자를 사용하면 배열의 길이가 2의 거듭 제곱이면 (비트 및) 연산자를 0 .. length - 1
사용하여 처럼 시퀀스를 쉽게 생성 할 수 있습니다 . 이것을 알면 위의 코드는&
i & length
int[] arr = new int[8];
int i = 0;
while (true){
print(arr[i]);
i = i + 1;
i = i & (arr.length - 1);
}
작동 방식은 다음과 같습니다. 에서는 바이너리 형식 1 감산 (2)의 전력이 각 숫자들만로 표현된다. 예를 들어 이진수의 3은 11
7 111
, 15는 15 등입니다 1111
. 이제 &
이진수로만 구성된 숫자에 숫자 가 있으면 어떻게됩니까 ? 우리가 이것을한다고 가정 해 봅시다.
num & 7;
num
7보다 작거나 같은 경우 결과는 1이있는 num
각 비트 &
가 자체 이기 때문 입니다. 경우 num
7보다 큰는 동안 &
작동 컴퓨터 물론 이후 제로로 남아있을 것입니다 제로 선두 (7 개)의 고려하게됩니다 &
만 후미 부분이 남아 작업을. 9 & 7
이진의 경우 처럼
1001 & 0111
결과는 0001이며 10 진수로 1이고 배열에서 두 번째 요소를 처리합니다.
마이크로 컨트롤러 출력의 일부 비트 만 변경하려고하지만 기록 할 레지스터가 바이트 인 경우 다음과 같은 작업을 수행합니다 (의사 코드).
char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs
물론 많은 마이크로 컨트롤러를 사용하면 각 비트를 개별적으로 변경할 수 있습니다.
숫자 mod (%)를 2의 거듭 제곱으로 계산하려면을 사용할 수 있습니다 yourNumber & 2^N-1
.이 경우와 같습니다 yourNumber % 2^N
.
number % 16 = number & 15;
number % 128 = number & 127;
이것은 아마도 2 ^ N 인 매우 큰 배당을 가진 모듈러스 연산의 대안으로 만 유용 할 것입니다. 그러나 .NET 2.0의 테스트에서는 모듈러스 연산에 대한 속도 향상이 무시할 만합니다. 현대 컴파일러가 이미 이와 같은 최적화를 수행하고 있다고 생각합니다. 아무도 이것에 대해 더 알고 있습니까?
%
나머지 작업 과 마찬가지로 실제로 다른 결과를 생성하므로 음수를 다르게 취급합니다. 그러나 전달하는 경우 uint
에 %
, C # 컴파일러가 실제로 비트를 사용하여 기계 코드를 생성하고 두 번째 인수는 2의 미리 알려진 전원이됩니다.
내 질문에는 실제 사용이 있습니다.
첫 번째 WM_KEYDOWN 알림에만 응답 하시겠습니까?
Windows C api 비트 30에서 WM_KEYDOWN 메시지를 사용할 때 이전 키 상태를 지정합니다. 메시지가 전송되기 전에 키가 다운되면 값이 1이고 키가 업이면 값이 0입니다.
이들은 주로 비트 단위 연산 (놀람)에 사용됩니다. 다음은 PHP 코드베이스에서 볼 수있는 실제 예제입니다.
문자 인코딩 :
if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {
데이터 구조 :
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
데이터베이스 드라이버 :
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
컴파일러 구현 :
opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;
C 프로그래밍을 처음 시작할 때마다 진리표와 그 모든 것을 이해했지만이 기사를 읽을 때까지 실제로 그것을 사용하는 방법을 모두 클릭하지는 않았습니다 . (실제 사례를 제공함)
x == 1
그리고 y == 2
, 다음 x || y
1로 평가하고 x | y
0 평가도 아니다 내가보고 할 이유 x^true
우수하다 !x
어떤 방법이다. 타이핑이 많고 관용적 x
이지 않으며 , 그렇지 않으면 bool
신뢰할 수 없습니다.
x^true
에 우수가 !x
있다 some->complicated().member->lookup ^= true;
단항 연산자의 어떤 화합물 할당 버전이 없습니다.